diff options
| author | 2018-08-22 16:56:58 -0400 | |
|---|---|---|
| committer | 2018-08-23 12:49:08 -0400 | |
| commit | ae7ced2f95425b997b9b62d1c89fd86d496bac13 (patch) | |
| tree | d7a0afef7f0032dd48b1ca8524a6c5ca616e1696 | |
| parent | d5796dd4f1cce3860241ab179e0bd07fbaf19864 (diff) | |
First kotlin
Convert one class to kotlin and provide a slight amount of guidance.
Test: existing tests
Change-Id: Ie8659765b674ac7b2d82ed3d343f387195c07d83
8 files changed, 258 insertions, 145 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index ae42882f917a..fbbc2a3d9dc4 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -15,3 +15,5 @@ api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREU strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT} hidden_api_txt_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} + +ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index c9ba26804e89..091350334835 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -32,6 +32,7 @@ java_library { android_library { name: "SystemUI-core", srcs: [ + "src/**/*.kt", "src/**/*.java", "src/**/I*.aidl", ], @@ -73,6 +74,59 @@ android_library { ], } +android_library { + name: "SystemUI-tests", + manifest: "tests/AndroidManifest.xml", + resource_dirs: [ + "tests/res", + "res-keyguard", + "res", + ], + srcs: [ + "tests/src/**/*.kt", + "tests/src/**/*.java", + "src/**/*.kt", + "src/**/*.java", + "src/**/I*.aidl", + ], + static_libs: [ + "SystemUIPluginLib", + "SystemUISharedLib", + "SettingsLib", + "androidx.car_car", + "androidx.legacy_legacy-support-v4", + "androidx.recyclerview_recyclerview", + "androidx.preference_preference", + "androidx.appcompat_appcompat", + "androidx.mediarouter_mediarouter", + "androidx.palette_palette", + "androidx.legacy_legacy-preference-v14", + "androidx.leanback_leanback", + "androidx.slice_slice-core", + "androidx.slice_slice-view", + "androidx.slice_slice-builders", + "androidx.arch.core_core-runtime", + "androidx.lifecycle_lifecycle-extensions", + "SystemUI-tags", + "SystemUI-proto", + "metrics-helper-lib", + "android-support-test", + "mockito-target-inline-minus-junit4", + "testables", + "truth-prebuilt", + ], + libs: [ + "android.test.runner", + "telephony-common", + "android.car", + "android.test.base", + ], + aaptflags: [ + "--extra-packages", + "com.android.keyguard:com.android.systemui", + ], +} + android_app { name: "SystemUI", static_libs: [ diff --git a/packages/SystemUI/docs/kotlin-in-sysui.md b/packages/SystemUI/docs/kotlin-in-sysui.md new file mode 100644 index 000000000000..1bf24f63498b --- /dev/null +++ b/packages/SystemUI/docs/kotlin-in-sysui.md @@ -0,0 +1,22 @@ +# Kotlin in SystemUI + +Queue "it's happening" gif. + +Kotlin is probably going to be a bit of a wild west for a while, but please +try to follow these guidelines as much as possible. + + - No semi-colons: they are optional, we probably don't want them in the + future, so let's just not add them. + - No DSLs: sysui is complicated enough as is, let's not add more layers at + the moment. + - Only use extension functions for keeping complex code locality: Don't use + extension functions to add methods to android classes that you always wished + were there, instead add them directly to the class and save us the extension. + - inline, reified, and de-compisition can all be great things: just make sure + you know what they do and why you are using them. + +# Recommended reading + + - [Kotlin](https://kotlinlang.org/) + - [AndroidX-KTX](https://www.youtube.com/watch?v=st1XVfkDWqk) + - [Performance and Kotlin tricks](https://www.youtube.com/watch?v=6P20npkvcb8) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java deleted file mode 100644 index 9d40f173bf26..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.os.LocaleList; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; - -import com.android.systemui.ConfigurationChangedReceiver; -import com.android.systemui.statusbar.policy.ConfigurationController; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class ConfigurationControllerImpl implements ConfigurationController, - ConfigurationChangedReceiver { - - private final ArrayList<ConfigurationListener> mListeners = new ArrayList<>(); - private final Configuration mLastConfig = new Configuration(); - private int mDensity; - private float mFontScale; - private boolean mInCarMode; - private int mUiMode; - private LocaleList mLocaleList; - - public ConfigurationControllerImpl(Context context) { - Configuration currentConfig = context.getResources().getConfiguration(); - mFontScale = currentConfig.fontScale; - mDensity = currentConfig.densityDpi; - mInCarMode = (currentConfig.uiMode & Configuration.UI_MODE_TYPE_MASK) - == Configuration.UI_MODE_TYPE_CAR; - mUiMode = currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK; - mLocaleList = currentConfig.getLocales(); - } - - @Override - public void notifyThemeChanged() { - ArrayList<ConfigurationListener> listeners = new ArrayList<>(mListeners); - - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onThemeChanged(); - } - }); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Avoid concurrent modification exception - ArrayList<ConfigurationListener> listeners = new ArrayList<>(mListeners); - - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onConfigChanged(newConfig); - } - }); - final float fontScale = newConfig.fontScale; - final int density = newConfig.densityDpi; - int uiMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK; - boolean uiModeChanged = uiMode != mUiMode; - if (density != mDensity || fontScale != mFontScale - || (mInCarMode && uiModeChanged)) { - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onDensityOrFontScaleChanged(); - } - }); - mDensity = density; - mFontScale = fontScale; - } - - final LocaleList localeList = newConfig.getLocales(); - if (!localeList.equals(mLocaleList)) { - mLocaleList = localeList; - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onLocaleListChanged(); - } - }); - } - - if (uiModeChanged) { - mUiMode = uiMode; - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onUiModeChanged(); - } - }); - } - - if ((mLastConfig.updateFrom(newConfig) & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { - listeners.forEach(l -> { - if (mListeners.contains(l)) { - l.onOverlayChanged(); - } - }); - } - } - - @Override - public void addCallback(ConfigurationListener listener) { - mListeners.add(listener); - listener.onDensityOrFontScaleChanged(); - } - - @Override - public void removeCallback(ConfigurationListener listener) { - mListeners.remove(listener); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt new file mode 100644 index 000000000000..81b596c0345e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.content.Context +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.os.LocaleList + +import com.android.systemui.ConfigurationChangedReceiver +import com.android.systemui.statusbar.policy.ConfigurationController + +import java.util.ArrayList + +class ConfigurationControllerImpl(context: Context) + : ConfigurationController, ConfigurationChangedReceiver { + + private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList() + private val lastConfig = Configuration() + private var density: Int = 0 + private var fontScale: Float = 0.toFloat() + private val inCarMode: Boolean + private var uiMode: Int = 0 + private var localeList: LocaleList? = null + + init { + val currentConfig = context.resources.configuration + fontScale = currentConfig.fontScale + density = currentConfig.densityDpi + inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK == + Configuration.UI_MODE_TYPE_CAR + uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK + localeList = currentConfig.locales + } + + override fun notifyThemeChanged() { + val listeners = ArrayList(listeners) + + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onThemeChanged() + } + } + + override fun onConfigurationChanged(newConfig: Configuration) { + // Avoid concurrent modification exception + val listeners = ArrayList(listeners) + + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onConfigChanged(newConfig) + } + val fontScale = newConfig.fontScale + val density = newConfig.densityDpi + val uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK + val uiModeChanged = uiMode != this.uiMode + if (density != this.density || fontScale != this.fontScale || + inCarMode && uiModeChanged) { + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onDensityOrFontScaleChanged() + } + this.density = density + this.fontScale = fontScale + } + + val localeList = newConfig.locales + if (localeList != this.localeList) { + this.localeList = localeList + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onLocaleListChanged() + } + } + + if (uiModeChanged) { + this.uiMode = uiMode + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onUiModeChanged() + } + } + + if (lastConfig.updateFrom(newConfig) and ActivityInfo.CONFIG_ASSETS_PATHS != 0) { + listeners.filterForEach({ this.listeners.contains(it) }) { + it.onOverlayChanged() + } + } + } + + override fun addCallback(listener: ConfigurationController.ConfigurationListener) { + listeners.add(listener) + listener.onDensityOrFontScaleChanged() + } + + override fun removeCallback(listener: ConfigurationController.ConfigurationListener) { + listeners.remove(listener) + } +} + +// This could be done with a Collection.filter and Collection.forEach, but Collection.filter +// creates a new array to store them in and we really don't need that here, so this provides +// a little more optimized inline version. +inline fun <T> Collection<T>.filterForEach(f: (T) -> Boolean, execute: (T) -> Unit) { + forEach { + if (f.invoke(it)) { + execute.invoke(it) + } + } +} diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 9ee55324efa2..6057614f26ee 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -21,28 +21,12 @@ LOCAL_MODULE_TAGS := tests LOCAL_JACK_FLAGS := --multi-dex native LOCAL_DX_FLAGS := --multi-dex -LOCAL_PROTOC_OPTIMIZE_TYPE := nano -LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/.. -LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors - LOCAL_PACKAGE_NAME := SystemUITests LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) \ - $(call all-Iaidl-files-under, src) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - LOCAL_STATIC_ANDROID_LIBRARIES := \ - SystemUI-core - -LOCAL_STATIC_JAVA_LIBRARIES := \ - metrics-helper-lib \ - android-support-test \ - mockito-target-inline-minus-junit4 \ - testables \ - truth-prebuilt \ + SystemUI-tests LOCAL_MULTILIB := both diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 64f96da09b08..8b1324a77a5e 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -72,6 +72,7 @@ tools:replace="android:authorities" android:authorities="${applicationId}.lifecycle-tests" android:exported="false" + android:enabled="false" android:multiprocess="true" /> <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider" android:authorities="com.android.systemui.test.keyguard.disabled" @@ -83,6 +84,7 @@ android:name="androidx.core.content.FileProvider" android:authorities="com.android.systemui.test.fileprovider" android:exported="false" + android:enabled="false" tools:replace="android:authorities" android:grantUriPermissions="true" /> </application> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt new file mode 100644 index 000000000000..0d13e975e56a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.support.test.filters.SmallTest +import android.testing.AndroidTestingRunner +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class ConfigurationControllerImplTest : SysuiTestCase() { + + private val mConfigurationController = + com.android.systemui.statusbar.phone.ConfigurationControllerImpl(mContext) + + @Test + fun testThemeChange() { + val listener = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener) + + mConfigurationController.notifyThemeChanged() + verify(listener).onThemeChanged() + } + + @Test + fun testRemoveListenerDuringCallback() { + val listener = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener) + val listener2 = mock(ConfigurationListener::class.java) + mConfigurationController.addCallback(listener2) + + doAnswer { + mConfigurationController.removeCallback(listener2) + null + }.`when`(listener).onThemeChanged() + + mConfigurationController.notifyThemeChanged() + verify(listener).onThemeChanged() + verify(listener2, never()).onThemeChanged() + } +} |