Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e052f7b0 authored by Jason Monk's avatar Jason Monk Committed by Android (Google) Code Review
Browse files

Merge "First kotlin"

parents 2d7b871a ae7ced2f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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}
+54 −0
Original line number Diff line number Diff line
@@ -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: [
+22 −0
Original line number Diff line number Diff line
# 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)
+0 −128
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+117 −0
Original line number Diff line number Diff line
/*
 * 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)
        }
    }
}
Loading