diff options
51 files changed, 1883 insertions, 691 deletions
diff --git a/api/current.txt b/api/current.txt index 6f2751d58dbe..2b1036d6da36 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22676,6 +22676,7 @@ package android.location { field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1 field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2 field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0 + field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000 field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100 field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200 field public static final int STATE_BIT_SYNC = 2; // 0x2 @@ -44382,6 +44383,7 @@ package android.telephony { method public int getChannelNumber(); method public String getMccString(); method public String getMncString(); + method public long getNci(); method public int getPci(); method public int getTac(); method public void writeToParcel(android.os.Parcel, int); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index da7e4daaf22b..29f67c7e6f9b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -31,6 +31,7 @@ import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto"; import "frameworks/base/core/proto/android/debug/enums.proto"; import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto"; +import "frameworks/base/core/proto/android/hardware/sensor/assist/enums.proto"; import "frameworks/base/core/proto/android/net/networkcapabilities.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto"; @@ -241,6 +242,9 @@ message Atom { BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171; DeviceIdentifierAccessDenied device_identifier_access_denied = 172; BubbleDeveloperErrorReported bubble_developer_error_reported = 173; + AssistGestureStageReported assist_gesture_stage_reported = 174; + AssistGestureFeedbackReported assist_gesture_feedback_reported = 175; + AssistGestureProgressReported assist_gesture_progress_reported = 176; } // Pulled events will start at field 10000. @@ -5522,3 +5526,35 @@ message TrainInfo { optional TrainExperimentIds train_experiment_id = 2; } + +/** + * Logs the gesture stage changed event. + * + * Logged from: + * frameworks/base/packages/SystemUI/ + */ +message AssistGestureStageReported { + optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1; +} + +/** + * Logs the feedback type. + * + * Logged from: + * frameworks/base/packages/SystemUI/ + */ +message AssistGestureFeedbackReported { + // Whether or not the gesture was used. + optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1; +} + +/** + * Logs the progress. + * + * Logged from: + * frameworks/base/packages/SystemUI/ + */ +message AssistGestureProgressReported { + // [0,100] progress for the assist gesture. + optional int32 progress = 1; +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 0eadd1dcd903..5f778da44a1c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -65,6 +65,7 @@ import android.net.Uri; import android.os.BadParcelableException; import android.os.Build; import android.os.Bundle; +import android.os.GraphicsEnvironment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -7708,6 +7709,8 @@ public class Activity extends ContextThemeWrapper } } + GraphicsEnvironment.getInstance().showAngleInUseDialogBox(this); + mActivityTransitionState.enterReady(this); dispatchActivityPostStarted(); } diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 269c781397ad..8813e400bee0 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -16,6 +16,7 @@ package android.os; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -30,6 +31,7 @@ import android.opengl.EGL14; import android.provider.Settings; import android.util.Base64; import android.util.Log; +import android.widget.Toast; import com.android.framework.protobuf.InvalidProtocolBufferException; @@ -222,9 +224,17 @@ public class GraphicsEnvironment { } - private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) { - List<String> valueList = null; - final String settingsValue = bundle.getString(globalSetting); + private static List<String> getGlobalSettingsString(ContentResolver contentResolver, + Bundle bundle, + String globalSetting) { + final List<String> valueList; + final String settingsValue; + + if (bundle != null) { + settingsValue = bundle.getString(globalSetting); + } else { + settingsValue = Settings.Global.getString(contentResolver, globalSetting); + } if (settingsValue != null) { valueList = new ArrayList<>(Arrays.asList(settingsValue.split(","))); @@ -246,17 +256,27 @@ public class GraphicsEnvironment { return -1; } - private static String getDriverForPkg(Bundle bundle, String packageName) { - final String allUseAngle = - bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE); + private static String getDriverForPkg(Context context, Bundle bundle, String packageName) { + final String allUseAngle; + if (bundle != null) { + allUseAngle = + bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE); + } else { + ContentResolver contentResolver = context.getContentResolver(); + allUseAngle = Settings.Global.getString(contentResolver, + Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE); + } if ((allUseAngle != null) && allUseAngle.equals("1")) { return sDriverMap.get(OpenGlDriverChoice.ANGLE); } - final List<String> globalSettingsDriverPkgs = getGlobalSettingsString( - bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS); - final List<String> globalSettingsDriverValues = getGlobalSettingsString( - bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES); + final ContentResolver contentResolver = context.getContentResolver(); + final List<String> globalSettingsDriverPkgs = + getGlobalSettingsString(contentResolver, bundle, + Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS); + final List<String> globalSettingsDriverValues = + getGlobalSettingsString(contentResolver, bundle, + Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES); // Make sure we have a good package name if ((packageName == null) || (packageName.isEmpty())) { @@ -308,7 +328,7 @@ public class GraphicsEnvironment { * True: Temporary rules file was loaded. * False: Temporary rules file was *not* loaded. */ - private boolean setupAngleWithTempRulesFile(Context context, + private static boolean setupAngleWithTempRulesFile(Context context, String packageName, String paths, String devOptIn) { @@ -372,7 +392,7 @@ public class GraphicsEnvironment { * True: APK rules file was loaded. * False: APK rules file was *not* loaded. */ - private boolean setupAngleRulesApk(String anglePkgName, + private static boolean setupAngleRulesApk(String anglePkgName, ApplicationInfo angleInfo, PackageManager pm, String packageName, @@ -405,23 +425,32 @@ public class GraphicsEnvironment { /** * Pull ANGLE whitelist from GlobalSettings and compare against current package */ - private boolean checkAngleWhitelist(Bundle bundle, String packageName) { + private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) { + final ContentResolver contentResolver = context.getContentResolver(); final List<String> angleWhitelist = - getGlobalSettingsString(bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST); + getGlobalSettingsString(contentResolver, bundle, + Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST); return angleWhitelist.contains(packageName); } /** * Pass ANGLE details down to trigger enable logic + * + * @param context + * @param bundle + * @param packageName + * @return true: ANGLE setup successfully + * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.) */ - public void setupAngle(Context context, Bundle bundle, PackageManager pm, String packageName) { + public boolean setupAngle(Context context, Bundle bundle, PackageManager pm, + String packageName) { if (packageName.isEmpty()) { Log.v(TAG, "No package name available yet, skipping ANGLE setup"); - return; + return false; } - final String devOptIn = getDriverForPkg(bundle, packageName); + final String devOptIn = getDriverForPkg(context, bundle, packageName); if (DEBUG) { Log.v(TAG, "ANGLE Developer option for '" + packageName + "' " + "set to: '" + devOptIn + "'"); @@ -439,11 +468,11 @@ public class GraphicsEnvironment { // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before // and can confidently answer yes/no based on the previously set developer // option value. - final boolean whitelisted = checkAngleWhitelist(bundle, packageName); + final boolean whitelisted = checkAngleWhitelist(context, bundle, packageName); final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT)); final boolean rulesCheck = (whitelisted || !defaulted); if (!rulesCheck) { - return; + return false; } if (whitelisted) { @@ -456,7 +485,7 @@ public class GraphicsEnvironment { final String anglePkgName = getAnglePackageName(pm); if (anglePkgName.isEmpty()) { Log.e(TAG, "Failed to find ANGLE package."); - return; + return false; } final ApplicationInfo angleInfo; @@ -464,7 +493,7 @@ public class GraphicsEnvironment { angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed"); - return; + return false; } final String abi = chooseAbi(angleInfo); @@ -480,12 +509,62 @@ public class GraphicsEnvironment { if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) { // We setup ANGLE with a temp rules file, so we're done here. - return; + return true; } if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) { // We setup ANGLE with rules from the APK, so we're done here. - return; + return true; + } + + return false; + } + + /** + * Determine if the "ANGLE In Use" dialog box should be shown. + */ + private boolean shouldShowAngleInUseDialogBox(Context context) { + try { + ContentResolver contentResolver = context.getContentResolver(); + final int showDialogBox = Settings.Global.getInt(contentResolver, + Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX); + + return (showDialogBox == 1); + } catch (Settings.SettingNotFoundException | SecurityException e) { + // Do nothing and move on + } + + // No setting, so assume false + return false; + } + + /** + * Determine if ANGLE should be used. + */ + private boolean shouldUseAngle(Context context, String packageName) { + // Need to make sure we are evaluating ANGLE usage for the correct circumstances + if (!setupAngle(context, null, context.getPackageManager(), packageName)) { + Log.v(TAG, "Package '" + packageName + "' should use not ANGLE"); + return false; + } + + final boolean useAngle = getShouldUseAngle(packageName); + Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'"); + + return useAngle; + } + + /** + * Show the ANGLE in Use Dialog Box + * @param context + */ + public void showAngleInUseDialogBox(Context context) { + final String packageName = context.getPackageName(); + + if (shouldShowAngleInUseDialogBox(context) && shouldUseAngle(context, packageName)) { + final String toastMsg = packageName + " is using ANGLE"; + final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG); + toast.show(); } } @@ -541,19 +620,19 @@ public class GraphicsEnvironment { if (gameDriverAllApps != 1) { // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS - if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS) - .contains(packageName)) { + if (getGlobalSettingsString(null, coreSettings, + Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) { if (DEBUG) { Log.w(TAG, packageName + " opts out from Game Driver."); } return false; } final boolean isOptIn = - getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS) - .contains(packageName); + getGlobalSettingsString(null, coreSettings, + Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName); if (!isOptIn - && !getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_WHITELIST) - .contains(packageName)) { + && !getGlobalSettingsString(null, coreSettings, + Settings.Global.GAME_DRIVER_WHITELIST).contains(packageName)) { if (DEBUG) { Log.w(TAG, packageName + " is not on the whitelist."); } @@ -660,4 +739,5 @@ public class GraphicsEnvironment { long driverVersionCode, String appPackageName); private static native void setAngleInfo(String path, String appPackage, String devOptIn, FileDescriptor rulesFd, long rulesOffset, long rulesLength); + private static native boolean getShouldUseAngle(String packageName); } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 735f4f253594..43c906495cb6 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1545,7 +1545,7 @@ public class StorageManager { public static boolean hasIsolatedStorage() { // Prefer to use snapshot for current boot when available return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT, - SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, false)); + SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true)); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c4019adb5d85..7f59d35586c1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6103,7 +6103,7 @@ public final class Settings { * Indicates which clock face to show on lock screen and AOD while docked. * @hide */ - private static final String DOCKED_CLOCK_FACE = "docked_clock_face"; + public static final String DOCKED_CLOCK_FACE = "docked_clock_face"; /** * Set by the system to track if the user needs to see the call to action for @@ -12318,6 +12318,14 @@ public final class Settings { "angle_whitelist"; /** + * Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver. + * The value is a boolean (1 or 0). + * @hide + */ + public static final String GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX = + "show_angle_in_use_dialog_box"; + + /** * Game Driver global preference for all Apps. * 0 = Default * 1 = All Apps use Game Driver diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 56558d04e50d..0eeef70a79a6 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -166,6 +166,26 @@ public final class MathUtils { } /** + * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link + * #lerp}{@code (a, b, s)} + * + * <p>If {@code a == b}, then this function will return 0. + */ + public static float lerpInv(float a, float b, float value) { + return a != b ? ((value - a) / (b - a)) : 0.0f; + } + + /** Returns the single argument constrained between [0.0, 1.0]. */ + public static float saturate(float value) { + return constrain(value, 0.0f, 1.0f); + } + + /** Returns the saturated (constrained between [0, 1]) result of {@link #lerpInv}. */ + public static float lerpInvSat(float a, float b, float value) { + return saturate(lerpInv(a, b, value)); + } + + /** * Returns an interpolated angle in degrees between a set of start and end * angles. * <p> @@ -195,6 +215,32 @@ public final class MathUtils { } /** + * Calculates a value in [rangeMin, rangeMax] that maps value in [valueMin, valueMax] to + * returnVal in [rangeMin, rangeMax]. + * <p> + * Always returns a constrained value in the range [rangeMin, rangeMax], even if value is + * outside [valueMin, valueMax]. + * <p> + * Eg: + * constrainedMap(0f, 100f, 0f, 1f, 0.5f) = 50f + * constrainedMap(20f, 200f, 10f, 20f, 20f) = 200f + * constrainedMap(20f, 200f, 10f, 20f, 50f) = 200f + * constrainedMap(10f, 50f, 10f, 20f, 5f) = 10f + * + * @param rangeMin minimum of the range that should be returned. + * @param rangeMax maximum of the range that should be returned. + * @param valueMin minimum of range to map {@code value} to. + * @param valueMax maximum of range to map {@code value} to. + * @param value to map to the range [{@code valueMin}, {@code valueMax}]. Note, can be outside + * this range, resulting in a clamped value. + * @return the mapped value, constrained to [{@code rangeMin}, {@code rangeMax}. + */ + public static float constrainedMap( + float rangeMin, float rangeMax, float valueMin, float valueMax, float value) { + return lerp(rangeMin, rangeMax, lerpInvSat(valueMin, valueMax, value)); + } + + /** * Perform Hermite interpolation between two values. * Eg: * smoothStep(0, 0.5f, 0.5f) = 1f diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 06207a9290d7..384cdbb3831c 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -174,7 +174,7 @@ public final class AccessibilityManager { final Handler.Callback mCallback; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) boolean mIsEnabled; int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 9c21ba60a034..ded3be4e4ef5 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -6020,9 +6020,6 @@ public class Editor { } updateSelection(event); - if (mTextView.hasSelection() && mEndHandle != null) { - mEndHandle.updateMagnifier(event); - } break; case MotionEvent.ACTION_UP: @@ -6030,9 +6027,6 @@ public class Editor { break; } updateSelection(event); - if (mEndHandle != null) { - mEndHandle.dismissMagnifier(); - } // No longer dragging to select text, let the parent intercept events. mTextView.getParent().requestDisallowInterceptTouchEvent(false); diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index e2e66ceb6fbe..95f99b760382 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -55,6 +55,11 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength); } +bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) { + ScopedUtfChars appNameChars(env, appName); + return android::GraphicsEnv::getInstance().shouldUseAngle(appNameChars.c_str()); +} + void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) { android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader( env, classLoader); @@ -81,6 +86,7 @@ const JNINativeMethod g_methods[] = { { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) }, { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) }, { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) }, + { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) }, { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) }, { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) }, { "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d04db92294d7..5cecf66a593c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -742,7 +742,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, return; } - if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, false))) { + if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true))) { if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) { storageSource = (mount_mode == MOUNT_EXTERNAL_FULL) ? "/mnt/runtime/full" : "/mnt/runtime/write"; diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 30b9b7847fb6..5497b8665cf0 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -610,6 +610,11 @@ enum Action { // CATEGORY: SETTINGS // OS: Q ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = 1646; + + // ACTION: An interaction with a Slice or other component in the Panel. + // CATEGORY: SETTINGS + // OS: Q + ACTION_PANEL_INTERACTION = 1658; } /** @@ -2214,4 +2219,16 @@ enum PageId { // CATEGORY: SETTINGS // OS: Q SET_NEW_PASSWORD_ACTIVITY = 1644; + + // Panel for Internet Connectivity + PANEL_INTERNET_CONNECTIVITY = 1654; + + // Panel for Volume + PANEL_VOLUME = 1655; + + // Panel for NFC + PANEL_NFC = 1656; + + // Panel for Media Output + PANEL_MEDIA_OUTPUT = 1657; } diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto new file mode 100644 index 000000000000..8c5841a32d54 --- /dev/null +++ b/core/proto/android/hardware/sensor/assist/enums.proto @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 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. + */ + +syntax = "proto2"; +package android.hardware.sensor.assist; + +option java_outer_classname = "AssistGestureProtoEnums"; +option java_multiple_files = true; + +enum AssistGestureStageEnum { + ASSIST_GESTURE_STAGE_UNKNOWN = 0; + ASSIST_GESTURE_STAGE_PROGRESS = 1; + ASSIST_GESTURE_STAGE_PRIMED = 2; + ASSIST_GESTURE_STAGE_DETECTED = 3; +} + +enum AssistGestureFeedbackEnum { + ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0; + ASSIST_GESTURE_FEEDBACK_NOT_USED = 1; + ASSIST_GESTURE_FEEDBACK_USED = 2; +}
\ No newline at end of file diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 39d61a15eb28..c9957f369473 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -451,6 +451,8 @@ message GlobalSettingsProto { // Game Driver - List of blacklists, each blacklist is a blacklist for // a specific Game Driver version optional SettingProto game_driver_blacklists = 14; + // ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG + optional SettingProto show_angle_in_use_dialog = 15; } optional Gpu gpu = 59; diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index b919553dd85d..c57b609023ca 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -494,6 +494,7 @@ public class SettingsBackupTest { Settings.Global.GAME_DRIVER_BLACKLISTS, Settings.Global.GAME_DRIVER_BLACKLIST, Settings.Global.GAME_DRIVER_WHITELIST, + Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT, @@ -620,6 +621,7 @@ public class SettingsBackupTest { Settings.Secure.DISABLED_PRINT_SERVICES, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, Settings.Secure.DISPLAY_DENSITY_FORCED, + Settings.Secure.DOCKED_CLOCK_FACE, Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index 237fc622dd2e..b93f07853242 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -23,7 +23,7 @@ namespace uirenderer { class FrameMetricsObserver : public VirtualLightRefBase { public: - virtual void notify(const int64_t* buffer); + virtual void notify(const int64_t* buffer) = 0; }; } // namespace uirenderer diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index 59eff6401deb..a545f2edd1bf 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -96,7 +96,7 @@ public final class GnssMeasurement implements Parcelable { STATE_TOW_DECODED, STATE_MSEC_AMBIGUOUS, STATE_SYMBOL_SYNC, STATE_GLO_STRING_SYNC, STATE_GLO_TOD_DECODED, STATE_BDS_D2_BIT_SYNC, STATE_BDS_D2_SUBFRAME_SYNC, STATE_GAL_E1BC_CODE_LOCK, STATE_GAL_E1C_2ND_CODE_LOCK, STATE_GAL_E1B_PAGE_SYNC, - STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN + STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN, STATE_2ND_CODE_LOCK }) @Retention(RetentionPolicy.SOURCE) public @interface State {} @@ -144,6 +144,9 @@ public final class GnssMeasurement implements Parcelable { */ public static final int STATE_GLO_TOD_KNOWN = (1<<15); + /** This GNSS measurement's tracking state has secondary code lock. */ + public static final int STATE_2ND_CODE_LOCK = (1 << 16); + /** * All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any * individual measurement.) @@ -517,6 +520,9 @@ public final class GnssMeasurement implements Parcelable { if ((mState & STATE_SBAS_SYNC) != 0) { builder.append("SbasSync|"); } + if ((mState & STATE_2ND_CODE_LOCK) != 0) { + builder.append("2ndCodeLock|"); + } int remainingStates = mState & ~STATE_ALL; if (remainingStates > 0) { @@ -531,96 +537,315 @@ public final class GnssMeasurement implements Parcelable { /** * Gets the received GNSS satellite time, at the measurement time, in nanoseconds. * - * <p>For GPS & QZSS, this is: - * <ul> - * <li>Received GPS Time-of-Week at the measurement time, in nanoseconds.</li> - * <li>The value is relative to the beginning of the current GPS week.</li> - * </ul> - * - * <p>Given the highest sync state that can be achieved, per each satellite, valid range - * for this field can be: - * <pre> - * Searching : [ 0 ] : STATE_UNKNOWN - * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set - * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set - * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC is set - * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED is set - * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set</pre> - * - * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has + * <p>The received satellite time is relative to the beginning of the system week for all + * constellations except for Glonass where it is relative to the beginning of the Glonass + * system day. + * + * <p>The table below indicates the valid range of the received GNSS satellite time. These + * ranges depend on the constellation and code being tracked and the state of the tracking + * algorithms given by the {@link #getState} method. The minimum value of this field is zero. + * The maximum value of this field is determined by looking across all of the state flags + * that are set, for the given constellation and code type, and finding the the maximum value + * in this table. + * + * <p>For example, for GPS L1 C/A, if STATE_TOW_KNOWN is set, this field can be any value from 0 + * to 1 week (in nanoseconds), and for GAL E1B code, if only STATE_GAL_E1BC_CODE_LOCK is set, + * then this field can be any value from 0 to 4 milliseconds (in nanoseconds.) + * + * <table border="1"> + * <thead> + * <tr> + * <td /> + * <td colspan="3"><strong>GPS/QZSS</strong></td> + * <td><strong>GLNS</strong></td> + * <td colspan="2"><strong>BDS</strong></td> + * <td colspan="3"><strong>GAL</strong></td> + * <td><strong>SBAS</strong></td> + * </tr> + * <tr> + * <td><strong>State Flag</strong></td> + * <td><strong>L1 C/A</strong></td> + * <td><strong>L5I</strong></td> + * <td><strong>L5Q</strong></td> + * <td><strong>L1OF</strong></td> + * <td><strong>B1I (D1)</strong></td> + * <td><strong>B1I (D2)</strong></td> + * <td><strong>E1B</strong></td> + * <td><strong>E1C</strong></td> + * <td><strong>E5AQ</strong></td> + * <td><strong>L1 C/A</strong></td> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td> + * <strong>STATE_UNKNOWN</strong> + * </td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * <td>0</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_CODE_LOCK</strong> + * </td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>1 ms</td> + * <td>-</td> + * <td>-</td> + * <td>1 ms</td> + * <td>1 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SYMBOL_SYNC</strong> + * </td> + * <td>20 ms (optional)</td> + * <td>10 ms</td> + * <td>1 ms (optional)</td> + * <td>10 ms</td> + * <td>20 ms (optional)</td> + * <td>2 ms</td> + * <td>4 ms (optional)</td> + * <td>4 ms (optional)</td> + * <td>1 ms (optional)</td> + * <td>2 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BIT_SYNC</strong> + * </td> + * <td>20 ms</td> + * <td>20 ms</td> + * <td>1 ms (optional)</td> + * <td>20 ms</td> + * <td>20 ms</td> + * <td>-</td> + * <td>8 ms</td> + * <td>-</td> + * <td>1 ms (optional)</td> + * <td>4 ms</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SUBFRAME_SYNC</strong> + * </td> + * <td>6s</td> + * <td>6s</td> + * <td>-</td> + * <td>2 s</td> + * <td>6 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_TOW_DECODED</strong> + * </td> + * <td colspan="2">1 week</td> + * <td>-</td> + * <td>1 day</td> + * <td colspan="2">1 week</td> + * <td colspan="2">1 week</td> + * <td>-</td> + * <td>1 week</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_TOW_KNOWN</strong> + * </td> + * <td colspan="3">1 week</td> + * <td>1 day</td> + * <td colspan="2">1 week</td> + * <td colspan="3">1 week</td> + * <td>1 week</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_STRING_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_TOD_DECODED</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 day</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GLO_TOD_KNOWN</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 day</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BDS_D2_BIT_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_BDS_D2_SUBFRAME_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>600 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1BC_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>4 ms</td> + * <td>4 ms</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1C_2ND_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_2ND_CODE_LOCK</strong> + * </td> + * <td>-</td> + * <td>10 ms (optional)</td> + * <td>20 ms</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>100 ms (optional)</td> + * <td>100 ms</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_GAL_E1B_PAGE_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>2 s</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * </tr> + * <tr> + * <td> + * <strong>STATE_SBAS_SYNC</strong> + * </td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>-</td> + * <td>1 s</td> + * </tr> + * </tbody> + * </table> + * + * <p>Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has * been determined from other sources. If TOW decoded is set then TOW Known must also be set. * - * <p>Note well: if there is any ambiguity in integer millisecond, {@code STATE_MSEC_AMBIGUOUS} - * must be set accordingly, in the 'state' field. - * - * <p>This value must be populated if 'state' != {@code STATE_UNKNOWN}. + * <p>Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be + * set accordingly, in the 'state' field. This value must be populated, unless the 'state' == + * STATE_UNKNOWN. * - * <p>For Glonass, this is: + * <p>Note on optional flags: * <ul> - * <li>Received Glonass time of day, at the measurement time in nanoseconds.</li> + * <li> For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the + * same as the bit length. + * <li> For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are + * implied by STATE_CODE_LOCK. + * <li> STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC. + * <li> STATE_2ND_CODE_LOCK for E1C is optional since it is implied by + * STATE_GAL_E1C_2ND_CODE_LOCK. + * <li> For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by + * STATE_GAL_E1BC_CODE_LOCK. * </ul> - * - * <p>Given the highest sync state that can be achieved, per each satellite, valid range for - * this field can be: - * <pre> - * Searching : [ 0 ] : STATE_UNKNOWN - * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set - * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC is set - * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set - * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC is set - * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED is set - * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set</pre> - * - * Note: Time of day known refers to the case where it is possibly not decoded over the air but - * has been determined from other sources. If Time of day decoded is set then Time of day known - * must also be set. - * - * <p>For Beidou, this is: - * <ul> - * <li>Received Beidou time of week, at the measurement time in nanoseconds.</li> - * </ul> - * - * <p>Given the highest sync state that can be achieved, per each satellite, valid range for - * this field can be: - * <pre> - * Searching : [ 0 ] : STATE_UNKNOWN - * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set - * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC is set - * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC is set - * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC is set - * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC is set - * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set - * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre> - * - * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has - * been determined from other sources. If TOW decoded is set then TOW Known must also be set. - * - * <p>For Galileo, this is: - * <ul> - * <li>Received Galileo time of week, at the measurement time in nanoseconds.</li> - * </ul> - * <pre> - * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set - * E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set - * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set - * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set - * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre> - * - * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has - * been determined from other sources. If TOW decoded is set then TOW Known must also be set. - * - * <p>For SBAS, this is: - * <ul> - * <li>Received SBAS time, at the measurement time in nanoseconds.</li> - * </ul> - * - * <p>Given the highest sync state that can be achieved, per each satellite, valid range for - * this field can be: - * <pre> - * Searching : [ 0 ] : STATE_UNKNOWN - * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set - * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set - * Message : [ 0 1s ] : STATE_SBAS_SYNC is set</pre> */ public long getReceivedSvTimeNanos() { return mReceivedSvTimeNanos; diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 730c409a91fb..a3db2d6a5055 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -146,6 +146,7 @@ LIBANDROID { AHardwareBuffer_getNativeHandle; # introduced=26 AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; # introduced=26 + AHardwareBuffer_lockPlanes; # introduced=29 AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26 AHardwareBuffer_release; # introduced=26 AHardwareBuffer_sendHandleToUnixSocket; # introduced=26 diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 2dba1d5bc257..c5a951ca5249 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -221,30 +221,6 @@ public class CarStatusBar extends StatusBar implements } } - @Override - public void destroy() { - mCarBatteryController.stopListening(); - mConnectedDeviceSignalController.stopListening(); - mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener); - mDrivingStateHelper.disconnectFromCarService(); - - if (mNavigationBarWindow != null) { - mWindowManager.removeViewImmediate(mNavigationBarWindow); - mNavigationBarView = null; - } - - if (mLeftNavigationBarWindow != null) { - mWindowManager.removeViewImmediate(mLeftNavigationBarWindow); - mLeftNavigationBarView = null; - } - - if (mRightNavigationBarWindow != null) { - mWindowManager.removeViewImmediate(mRightNavigationBarWindow); - mRightNavigationBarView = null; - } - super.destroy(); - } - @Override protected void makeStatusBarView() { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index b9a5f2347f16..8ea0f4b6ba61 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -53,6 +53,7 @@ import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.android.internal.util.CollectionUtils; import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; @@ -566,9 +567,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro AccessPoint accessPoint = getCachedOrCreate(entry.getValue(), cachedAccessPoints); - if (mLastInfo != null && mLastNetworkInfo != null) { - accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo); - } // Update the matching config if there is one, to populate saved network info accessPoint.update(configsByKey.get(entry.getKey())); @@ -578,68 +576,20 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values()); - // Add a unique Passpoint R1 AccessPoint for each Passpoint profile's FQDN. - List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans = - mWifiManager.getAllMatchingWifiConfigs(cachedScanResults); - Set<String> seenFQDNs = new ArraySet<>(); - for (Pair<WifiConfiguration, - Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) { - WifiConfiguration config = pairing.first; - - List<ScanResult> scanResults = new ArrayList<>(); + // Add a unique Passpoint AccessPoint for each Passpoint profile's FQDN. + accessPoints.addAll(updatePasspointAccessPoints( + mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints)); - List<ScanResult> homeScans = - pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK); - List<ScanResult> roamingScans = - pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK); + // Add OSU Provider AccessPoints + accessPoints.addAll(updateOsuAccessPoints( + mWifiManager.getMatchingOsuProviders(cachedScanResults), cachedAccessPoints)); - if (homeScans == null) { - homeScans = new ArrayList<>(); - } - if (roamingScans == null) { - roamingScans = new ArrayList<>(); - } - - // TODO(b/118705403): Differentiate home network vs roaming network for summary info - if (!homeScans.isEmpty()) { - scanResults.addAll(homeScans); - } else { - scanResults.addAll(roamingScans); - } - - if (seenFQDNs.add(config.FQDN)) { - int bestRssi = Integer.MIN_VALUE; - for (ScanResult result : scanResults) { - if (result.level >= bestRssi) { - bestRssi = result.level; - config.SSID = AccessPoint.convertToQuotedString(result.SSID); - } - } - - AccessPoint accessPoint = - getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config); - accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo); - accessPoints.add(accessPoint); - } - } - - // Add Passpoint OSU Provider AccessPoints - Map<OsuProvider, List<ScanResult>> providersAndScans = - mWifiManager.getMatchingOsuProviders(cachedScanResults); - Set<OsuProvider> alreadyProvisioned = mWifiManager - .getMatchingPasspointConfigsForOsuProviders( - providersAndScans.keySet()).keySet(); - for (OsuProvider provider : providersAndScans.keySet()) { - if (!alreadyProvisioned.contains(provider)) { - AccessPoint accessPointOsu = - getCachedOrCreateOsu(providersAndScans.get(provider), - cachedAccessPoints, provider); - accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo); - accessPoints.add(accessPointOsu); + if (mLastInfo != null && mLastNetworkInfo != null) { + for (AccessPoint ap : accessPoints) { + ap.update(connectionConfig, mLastInfo, mLastNetworkInfo); } } - // If there were no scan results, create an AP for the currently connected network (if // it exists). if (accessPoints.isEmpty() && connectionConfig != null) { @@ -686,7 +636,67 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro } @VisibleForTesting - AccessPoint getCachedOrCreate( + List<AccessPoint> updatePasspointAccessPoints( + List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans, + List<AccessPoint> accessPointCache) { + List<AccessPoint> accessPoints = new ArrayList<>(); + + Set<String> seenFQDNs = new ArraySet<>(); + for (Pair<WifiConfiguration, + Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) { + WifiConfiguration config = pairing.first; + if (seenFQDNs.add(config.FQDN)) { + List<ScanResult> apScanResults = new ArrayList<>(); + + List<ScanResult> homeScans = + pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK); + List<ScanResult> roamingScans = + pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK); + + // TODO(b/118705403): Differentiate home network vs roaming network for summary info + if (!CollectionUtils.isEmpty(homeScans)) { + apScanResults.addAll(homeScans); + } else if (!CollectionUtils.isEmpty(roamingScans)) { + apScanResults.addAll(roamingScans); + } + + int bestRssi = Integer.MIN_VALUE; + for (ScanResult result : apScanResults) { + if (result.level >= bestRssi) { + bestRssi = result.level; + config.SSID = AccessPoint.convertToQuotedString(result.SSID); + } + } + + AccessPoint accessPoint = + getCachedOrCreatePasspoint(apScanResults, accessPointCache, config); + accessPoints.add(accessPoint); + } + } + return accessPoints; + } + + @VisibleForTesting + List<AccessPoint> updateOsuAccessPoints( + Map<OsuProvider, List<ScanResult>> providersAndScans, + List<AccessPoint> accessPointCache) { + List<AccessPoint> accessPoints = new ArrayList<>(); + + Set<OsuProvider> alreadyProvisioned = mWifiManager + .getMatchingPasspointConfigsForOsuProviders( + providersAndScans.keySet()).keySet(); + for (OsuProvider provider : providersAndScans.keySet()) { + if (!alreadyProvisioned.contains(provider)) { + AccessPoint accessPointOsu = + getCachedOrCreateOsu(providersAndScans.get(provider), + accessPointCache, provider); + accessPoints.add(accessPointOsu); + } + } + return accessPoints; + } + + private AccessPoint getCachedOrCreate( List<ScanResult> scanResults, List<AccessPoint> cache) { AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0))); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index 42eb0b940938..7d227883b1fe 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,11 +49,15 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkScoreCache; import android.net.wifi.WifiSsid; +import android.net.wifi.hotspot2.OsuProvider; +import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; import android.provider.Settings; +import android.util.ArraySet; +import android.util.Pair; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -74,7 +79,10 @@ import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -94,6 +102,8 @@ public class WifiTrackerTest { private static final int RSSI_1 = -30; private static final byte SCORE_1 = 10; private static final int BADGE_1 = AccessPoint.Speed.MODERATE; + private static final String FQDN_1 = "fqdn1"; + private static final String PROVIDER_FRIENDLY_NAME_1 = "providerFriendlyName1"; private static final String SSID_2 = "ssid2"; private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA"; @@ -102,6 +112,8 @@ public class WifiTrackerTest { private static final int RSSI_2 = -30; private static final byte SCORE_2 = 15; private static final int BADGE_2 = AccessPoint.Speed.FAST; + private static final String FQDN_2 = "fqdn2"; + private static final String PROVIDER_FRIENDLY_NAME_2 = "providerFriendlyName2"; private static final String SSID_3 = "ssid3"; private static final String BSSID_3 = "CC:00:00:00:00:00"; @@ -271,6 +283,61 @@ public class WifiTrackerTest { 0 /* microsecond timestamp */); } + private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) { + WifiConfiguration config = spy(new WifiConfiguration()); + config.FQDN = fqdn; + config.providerFriendlyName = friendlyName; + when(config.isPasspoint()).thenReturn(true); + return config; + } + + private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> + createPasspointMatchingWifiConfigsWithDuplicates() { + List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList = + new ArrayList<>(); + Map<Integer, List<ScanResult>> mapping = new HashMap<>(); + + mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Arrays.asList(buildScanResult1())); + + WifiConfiguration passpointConfig1 = + buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1); + WifiConfiguration passpointConfig2 = + buildPasspointConfiguration(FQDN_2, PROVIDER_FRIENDLY_NAME_2); + + matchingList.add(new Pair(passpointConfig1, mapping)); + matchingList.add(new Pair(passpointConfig1, mapping)); + matchingList.add(new Pair(passpointConfig2, mapping)); + matchingList.add(new Pair(passpointConfig2, mapping)); + + return matchingList; + } + + private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> + createPasspointMatchingWifiConfigWithScanResults( + List<ScanResult> homeList, List<ScanResult> roamingList) { + List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList = + new ArrayList<>(); + Map<Integer, List<ScanResult>> mapping = new HashMap<>(); + + if (homeList != null) { + mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, homeList); + } + if (roamingList != null) { + mapping.put(WifiManager.PASSPOINT_ROAMING_NETWORK, roamingList); + } + + matchingList.add(new Pair(buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1), + mapping)); + + return matchingList; + } + + private static OsuProvider buildOsuProvider(String friendlyName) { + Map<String, String> friendlyNames = new HashMap<>(); + friendlyNames.put("en", friendlyName); + return new OsuProvider(null, friendlyNames, null, null, null, null, null); + } + private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults( Intent ... intents) throws InterruptedException { @@ -926,4 +993,172 @@ public class WifiTrackerTest { assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1); assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2); } + + /** + * Verifies that updatePasspointAccessPoints will only return AccessPoints whose + * isPasspoint() evaluates as true. + */ + @Test + public void updatePasspointAccessPoints_returnedAccessPointsArePasspoint() { + WifiTracker tracker = createMockedWifiTracker(); + + List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints( + createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>()); + + assertTrue(passpointAccessPoints.size() != 0); + for (AccessPoint ap : passpointAccessPoints) { + assertTrue(ap.isPasspoint()); + } + } + + /** + * Verifies that updatePasspointAccessPoints will return the same amount of AccessPoints as + * unique WifiConfigurations, even if duplicate FQDNs exist. + */ + @Test + public void updatePasspointAccessPoints_ignoresDuplicateFQDNs() { + WifiTracker tracker = createMockedWifiTracker(); + + // Process matching list of four configs with two duplicate FQDNs. + List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints( + createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>()); + + // Should have 2 APs with unique FQDNs, ignoring the 2 duplicate FQDNs. + assertThat(passpointAccessPoints).hasSize(2); + + Set<String> fqdns = new ArraySet<>(Arrays.asList(FQDN_1, FQDN_2)); + + assertTrue(fqdns.remove(passpointAccessPoints.get(0).getConfig().FQDN)); + assertTrue(fqdns.remove(passpointAccessPoints.get(1).getConfig().FQDN)); + } + + /** + * Verifies that updatePasspointAccessPoints will return matching cached APs and update their + * scan results instead of creating new APs. + */ + @Test + public void updatePasspointAccessPoints_usesCachedAccessPoints() { + WifiTracker tracker = createMockedWifiTracker(); + + ScanResult result = buildScanResult1(); + + List<AccessPoint> passpointAccessPointsFirstUpdate = tracker.updatePasspointAccessPoints( + createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result), + null), new ArrayList<>()); + List<AccessPoint> cachedAccessPoints = new ArrayList<>(passpointAccessPointsFirstUpdate); + + int prevRssi = result.level; + int newRssi = prevRssi + 10; + result.level = newRssi; + + List<AccessPoint> passpointAccessPointsSecondUpdate = tracker.updatePasspointAccessPoints( + createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result), + null), cachedAccessPoints); + + // Verify second update AP is the same object as the first update AP + assertThat(passpointAccessPointsFirstUpdate.get(0)) + .isSameAs(passpointAccessPointsSecondUpdate.get(0)); + // Verify second update AP has the average of the first and second update RSSIs + assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi()) + .isEqualTo((prevRssi + newRssi) / 2); + } + + /** + * Verifies that updateOsuAccessPoints will only return AccessPoints whose + * isOsuProvider() evaluates as true. + */ + @Test + public void updateOsuAccessPoints_returnedAccessPointsAreOsuProviders() { + WifiTracker tracker = createMockedWifiTracker(); + + Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>(); + providersAndScans.put( + buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1())); + providersAndScans.put( + buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2())); + + List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints( + providersAndScans, new ArrayList<>()); + + assertThat(osuAccessPoints).hasSize(2); + for (AccessPoint ap: osuAccessPoints) { + assertThat(ap.isOsuProvider()).isTrue(); + } + } + + /** + * Verifies that updateOsuAccessPoints will not return Osu AccessPoints for already provisioned + * networks + */ + @Test + public void updateOsuAccessPoints_doesNotReturnAlreadyProvisionedOsuAccessPoints() { + WifiTracker tracker = createMockedWifiTracker(); + + // Start with two Osu Providers + Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>(); + providersAndScans.put( + buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1())); + providersAndScans.put( + buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2())); + + // First update + List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints( + providersAndScans, new ArrayList<>()); + + // Make sure both Osu Providers' APs are returned + assertThat(osuAccessPoints).hasSize(2); + List<String> friendlyNames = Arrays.asList( + osuAccessPoints.get(0).getTitle(), osuAccessPoints.get(1).getTitle()); + assertThat(friendlyNames) + .containsExactly(PROVIDER_FRIENDLY_NAME_1, PROVIDER_FRIENDLY_NAME_2); + + // Simulate Osu Provider 1 being provisioned + Map<OsuProvider, PasspointConfiguration> matchingPasspointConfigForOsuProvider = + new HashMap<>(); + matchingPasspointConfigForOsuProvider.put(buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), null); + when(mockWifiManager.getMatchingPasspointConfigsForOsuProviders(any())).thenReturn( + matchingPasspointConfigForOsuProvider); + + // Second update + osuAccessPoints = tracker.updateOsuAccessPoints( + providersAndScans, new ArrayList<>()); + + // Returned AP should only be for Osu Provider 2 + assertThat(osuAccessPoints).hasSize(1); + assertThat(osuAccessPoints.get(0).getTitle()).isEqualTo(PROVIDER_FRIENDLY_NAME_2); + } + + /** + * Verifies that updateOsuAccessPoints will return matching cached APs and update their + * scan results instead of creating new APs. + */ + @Test + public void updateOsuAccessPoints_usesCachedAccessPoints() { + WifiTracker tracker = createMockedWifiTracker(); + + ScanResult result = buildScanResult1(); + + Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>(); + providersAndScans.put( + buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(result)); + + List<AccessPoint> osuAccessPointsFirstUpdate = tracker.updateOsuAccessPoints( + providersAndScans, new ArrayList<>()); + List<AccessPoint> cachedAccessPoints = new ArrayList<>(osuAccessPointsFirstUpdate); + + // New RSSI for second update + int prevRssi = result.level; + int newRssi = prevRssi + 10; + result.level = newRssi; + + List<AccessPoint> osuAccessPointsSecondUpdate = tracker.updateOsuAccessPoints( + providersAndScans, cachedAccessPoints); + + // Verify second update AP is the same object as the first update AP + assertTrue(osuAccessPointsFirstUpdate.get(0) + == osuAccessPointsSecondUpdate.get(0)); + // Verify second update AP has the average of the first and second update RSSIs + assertThat(osuAccessPointsSecondUpdate.get(0).getRssi()) + .isEqualTo((prevRssi + newRssi) / 2); + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 3caa139ab998..db4b131a0f6f 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -698,6 +698,9 @@ class SettingsProtoDumpUtil { Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, GlobalSettingsProto.Gpu.ANGLE_WHITELIST); dumpSetting(s, p, + Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, + GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG); + dumpSetting(s, p, Settings.Global.GPU_DEBUG_LAYER_APP, GlobalSettingsProto.Gpu.DEBUG_LAYER_APP); dumpSetting(s, p, diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java index 95981427b642..078108d658ee 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java @@ -15,6 +15,7 @@ */ package com.android.keyguard.clock; +import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; @@ -25,16 +26,18 @@ import android.os.Looper; import android.provider.Settings; import android.view.LayoutInflater; +import androidx.annotation.VisibleForTesting; + import com.android.keyguard.R; +import com.android.systemui.dock.DockManager; +import com.android.systemui.dock.DockManager.DockEventListener; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.function.Consumer; -import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Singleton; @@ -45,7 +48,6 @@ import javax.inject.Singleton; @Singleton public final class ClockManager { - private final LayoutInflater mLayoutInflater; private final ContentResolver mContentResolver; private final List<ClockInfo> mClockInfos = new ArrayList<>(); @@ -62,7 +64,6 @@ public final class ClockManager { } } }; - private final ExtensionController mExtensionController; /** * Used to select between plugin or default implementations of ClockPlugin interface. @@ -72,13 +73,35 @@ public final class ClockManager { * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads. */ private final Consumer<ClockPlugin> mClockPluginConsumer = this::setClockPlugin; + /** + * Supplier of default ClockPlugin implementation. + */ + private final DefaultClockSupplier mDefaultClockSupplier; + /** + * Observe changes to dock state to know when to switch the clock face. + */ + private final DockEventListener mDockEventListener = + new DockEventListener() { + @Override + public void onEvent(int event) { + final boolean isDocked = (event == DockManager.STATE_DOCKED + || event == DockManager.STATE_DOCKED_HIDE); + mDefaultClockSupplier.setDocked(isDocked); + if (mClockExtension != null) { + mClockExtension.reload(); + } + } + }; + @Nullable + private final DockManager mDockManager; private final List<ClockChangedListener> mListeners = new ArrayList<>(); @Inject - public ClockManager(Context context, ExtensionController extensionController) { + public ClockManager(Context context, ExtensionController extensionController, + @Nullable DockManager dockManager) { mExtensionController = extensionController; - mLayoutInflater = LayoutInflater.from(context); + mDockManager = dockManager; mContentResolver = context.getContentResolver(); Resources res = context.getResources(); @@ -110,6 +133,9 @@ public final class ClockManager { .setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.type_thumbnail)) .setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.type_preview)) .build()); + + mDefaultClockSupplier = new DefaultClockSupplier(new SettingsWrapper(mContentResolver), + LayoutInflater.from(context)); } /** @@ -154,41 +180,32 @@ public final class ClockManager { mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), false, mContentObserver); + mContentResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE), + false, mContentObserver); + if (mDockManager != null) { + mDockManager.addListener(mDockEventListener); + } mClockExtension = mExtensionController.newExtension(ClockPlugin.class) .withPlugin(ClockPlugin.class) .withCallback(mClockPluginConsumer) - // Using withDefault even though this isn't the default as a workaround. - // ExtensionBuilder doesn't provide the ability to supply a ClockPlugin - // instance based off of the value of a setting. Since multiple "default" - // can be provided, using a supplier that changes the settings value. - // A null return will cause Extension#reload to look at the next "default" - // supplier. - .withDefault( - new SettingsGattedSupplier( - mContentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, - BubbleClockController.class.getName(), - () -> BubbleClockController.build(mLayoutInflater))) - .withDefault( - new SettingsGattedSupplier( - mContentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, - StretchAnalogClockController.class.getName(), - () -> StretchAnalogClockController.build(mLayoutInflater))) - .withDefault( - new SettingsGattedSupplier( - mContentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, - TypeClockController.class.getName(), - () -> TypeClockController.build(mLayoutInflater))) + .withDefault(mDefaultClockSupplier) .build(); } private void unregister() { mContentResolver.unregisterContentObserver(mContentObserver); + if (mDockManager != null) { + mDockManager.removeListener(mDockEventListener); + } mClockExtension.destroy(); } + @VisibleForTesting + boolean isDocked() { + return mDefaultClockSupplier.isDocked(); + } + /** * Listener for events that should cause the custom clock face to change. */ @@ -200,44 +217,4 @@ public final class ClockManager { */ void onClockChanged(ClockPlugin clock); } - - /** - * Supplier that only gets an instance when a settings value matches expected value. - */ - private static class SettingsGattedSupplier implements Supplier<ClockPlugin> { - - private final ContentResolver mContentResolver; - private final String mKey; - private final String mValue; - private final Supplier<ClockPlugin> mSupplier; - - /** - * Constructs a supplier that changes secure setting key against value. - * - * @param contentResolver Used to look up settings value. - * @param key Settings key. - * @param value If the setting matches this values that get supplies a ClockPlugin - * instance. - * @param supplier Supplier of ClockPlugin instance, only used if the setting - * matches value. - */ - SettingsGattedSupplier(ContentResolver contentResolver, String key, String value, - Supplier<ClockPlugin> supplier) { - mContentResolver = contentResolver; - mKey = key; - mValue = value; - mSupplier = supplier; - } - - /** - * Returns null if the settings value doesn't match the expected value. - * - * A null return causes Extension#reload to skip this supplier and move to the next. - */ - @Override - public ClockPlugin get() { - final String currentValue = Settings.Secure.getString(mContentResolver, mKey); - return Objects.equals(currentValue, mValue) ? mSupplier.get() : null; - } - } } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java new file mode 100644 index 000000000000..7fdd2357bc8e --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 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.keyguard.clock; + +import android.util.ArrayMap; +import android.view.LayoutInflater; + +import com.android.systemui.plugins.ClockPlugin; + +import java.util.Map; +import java.util.function.Supplier; + +/** + * Supplier that only gets an instance when a settings value matches expected value. + */ +public class DefaultClockSupplier implements Supplier<ClockPlugin> { + + private final SettingsWrapper mSettingsWrapper; + /** + * Map from expected value stored in settings to supplier of custom clock face. + */ + private final Map<String, Supplier<ClockPlugin>> mClocks = new ArrayMap<>(); + /** + * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face + * to show. + */ + private boolean mIsDocked; + + /** + * Constructs a supplier that changes secure setting key against value. + * + * @param settingsWrapper Wrapper around settings used to look up the custom clock face. + * @param layoutInflater Provided to clocks as dependency to inflate clock views. + */ + public DefaultClockSupplier(SettingsWrapper settingsWrapper, LayoutInflater layoutInflater) { + mSettingsWrapper = settingsWrapper; + + mClocks.put(BubbleClockController.class.getName(), + () -> BubbleClockController.build(layoutInflater)); + mClocks.put(StretchAnalogClockController.class.getName(), + () -> StretchAnalogClockController.build(layoutInflater)); + mClocks.put(TypeClockController.class.getName(), + () -> TypeClockController.build(layoutInflater)); + } + + /** + * Sets the dock state. + * + * @param isDocked True when docked, false otherwise. + */ + public void setDocked(boolean isDocked) { + mIsDocked = isDocked; + } + + boolean isDocked() { + return mIsDocked; + } + + /** + * Get the custom clock face based on values in settings. + * + * @return Custom clock face, null if the settings value doesn't match a custom clock. + */ + @Override + public ClockPlugin get() { + ClockPlugin plugin = null; + if (mIsDocked) { + final String name = mSettingsWrapper.getDockedClockFace(); + if (name != null) { + Supplier<ClockPlugin> supplier = mClocks.get(name); + if (supplier != null) { + plugin = supplier.get(); + if (plugin != null) { + return plugin; + } + } + } + } + final String name = mSettingsWrapper.getLockScreenCustomClockFace(); + if (name != null) { + Supplier<ClockPlugin> supplier = mClocks.get(name); + if (supplier != null) { + plugin = supplier.get(); + } + } + return plugin; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java new file mode 100644 index 000000000000..58e11553af9d --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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.keyguard.clock; + +import android.content.ContentResolver; +import android.provider.Settings; + +/** + * Wrapper around Settings used for testing. + */ +public class SettingsWrapper { + + private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE; + private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE; + + private ContentResolver mContentResolver; + + public SettingsWrapper(ContentResolver contentResolver) { + mContentResolver = contentResolver; + } + + /** + * Gets the value stored in settings for the custom clock face. + */ + public String getLockScreenCustomClockFace() { + return Settings.Secure.getString(mContentResolver, CUSTOM_CLOCK_FACE); + } + + /** + * Gets the value stored in settings for the clock face to use when docked. + */ + public String getDockedClockFace() { + return Settings.Secure.getString(mContentResolver, DOCKED_CLOCK_FACE); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 755d6fcffb43..d27a90332ac5 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -31,6 +31,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.assist.AssistManager; import com.android.systemui.classifier.FalsingManager; +import com.android.systemui.dock.DockManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -228,6 +229,16 @@ public class SystemUIFactory { return SysUiServiceProvider.getComponent(context, StatusBar.class); } + /** + * Provides DockManager. + */ + @Singleton + @Provides + @Nullable + public DockManager providesDockManager(Context context) { + return SysUiServiceProvider.getComponent(context, DockManager.class); + } + @Module protected static class ContextHolder { private Context mContext; diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 4d708908975e..038f4912e40f 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -290,10 +290,6 @@ public class AssistManager implements ConfigurationChangedReceiver { return mAssistUtils.isSessionRunning(); } - public void destroy() { - mWindowManager.removeViewImmediate(mView); - } - private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) { replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME, isService); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index e11ec2d24e29..2edea789d820 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -158,18 +158,6 @@ public class NavigationBarController implements DisplayListener, Callbacks { }); } - /** Removes navigation bars. */ - public void destroy() { - mDisplayManager.unregisterDisplayListener(this); - if (mNavigationBars.size() > 0) { - for (int i = 0; i < mNavigationBars.size(); i++) { - int displayId = mNavigationBars.keyAt(i); - removeNavigationBar(displayId); - } - mNavigationBars.clear(); - } - } - private void removeNavigationBar(int displayId) { NavigationBarFragment navBar = mNavigationBars.get(displayId); if (navBar != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index c25b7cfd804c..1cc6dc391c1d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -42,8 +42,6 @@ public interface NotificationLockscreenUserManager { /** Adds a listener to be notified when the current user changes. */ void addUserChangedListener(UserChangedListener listener); - void destroy(); - SparseArray<UserInfo> getCurrentProfiles(); void setLockscreenPublicMode(boolean isProfilePublic, int userId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 6a49b804f5ba..9cb6f11fb558 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -550,12 +550,6 @@ public class NotificationLockscreenUserManagerImpl implements return mKeyguardMonitor.isSecure() || mLockPatternUtils.isSecure(userId); } - public void destroy() { - mContext.unregisterReceiver(mBaseBroadcastReceiver); - mContext.unregisterReceiver(mAllUsersReceiver); - mListeners.clear(); - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NotificationLockscreenUserManager state:"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java index 88f4ca239af4..769cbb7b984c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java @@ -61,11 +61,6 @@ public class NotificationListController { mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); } - /** Should be called when the list controller is being destroyed. */ - public void destroy() { - mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener); - } - @SuppressWarnings("FieldCanBeLocal") private final NotificationEntryListener mEntryListener = new NotificationEntryListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 7105876907bf..fbf1e310abf2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -578,6 +578,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void onDensityOrFontScaleChanged() { + reinflateViews(); + } + + private void reinflateViews() { inflateFooterView(); inflateEmptyShadeView(); updateFooter(); @@ -608,6 +612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mCornerRadius = newRadius; invalidate(); } + reinflateViews(); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 4c1c0a4b4e58..de0e194ef90c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -141,10 +141,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, mAnimationStateHandler = handler; } - public void destroy() { - Dependency.get(StatusBarStateController.class).removeCallback(this); - } - private void initResources() { Resources resources = mContext.getResources(); mStatusBarHeight = resources.getDimensionPixelSize( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 18711c0d1ae3..2799191a886f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -284,25 +284,6 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, }); } - public void destroy() { - mRotationLockController.removeCallback(this); - mBluetooth.removeCallback(this); - mProvisionedController.removeCallback(this); - mZenController.removeCallback(this); - mCast.removeCallback(mCastCallback); - mHotspot.removeCallback(mHotspotCallback); - mNextAlarmController.removeCallback(mNextAlarmCallback); - mDataSaver.removeCallback(this); - mKeyguardMonitor.removeCallback(this); - mPrivacyItemController.removeCallback(this); - SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this); - mContext.unregisterReceiver(mIntentReceiver); - - NotificationManager noMan = mContext.getSystemService(NotificationManager.class); - mCurrentNotifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS, - new UserHandle(v.second))); - } - @Override public void onZenChanged(int zen) { updateVolumeZen(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 9f3bec60cb6d..849570937ea4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2843,38 +2843,6 @@ public class StatusBar extends SystemUI implements DemoMode, startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); } - public void destroy() { - // Begin old BaseStatusBar.destroy(). - mContext.unregisterReceiver(mBannerActionBroadcastReceiver); - mLockscreenUserManager.destroy(); - try { - mNotificationListener.unregisterAsSystemService(); - } catch (RemoteException e) { - // Ignore. - } - mNotificationListController.destroy(); - // End old BaseStatusBar.destroy(). - if (mStatusBarWindow != null) { - mWindowManager.removeViewImmediate(mStatusBarWindow); - mStatusBarWindow = null; - } - mNavigationBarController.destroy(); - mContext.unregisterReceiver(mBroadcastReceiver); - mContext.unregisterReceiver(mDemoReceiver); - mAssistManager.destroy(); - mHeadsUpManager.destroy(); - mStatusBarStateController.removeCallback(this); - - if (mQSPanel != null && mQSPanel.getHost() != null) { - mQSPanel.getHost().destroy(); - } - Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null); - mDeviceProvisionedController.removeCallback(mUserSetupObserver); - Dependency.get(ConfigurationController.class).removeCallback(this); - mZenController.removeCallback(this); - mAppOpsController.removeCallback(APP_OPS, this); - } - private boolean mDemoModeAllowed; private boolean mDemoMode; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index e9705ff35a4d..3ce66c5de372 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -258,6 +258,11 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } } + @Override + public void onOverlayChanged() { + onDensityOrFontScaleChanged(); + } + private void updateNotificationOnUiModeChanged() { ArrayList<NotificationEntry> userNotifications = mEntryManager.getNotificationData().getNotificationsForCurrentUser(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java new file mode 100644 index 000000000000..f813ac693d42 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 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.keyguard.clock; + +import static com.google.common.truth.Truth.assertThat; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.LeakCheck; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dock.DockManager; +import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.utils.leaks.FakeExtensionController; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public final class ClockManagerTest extends SysuiTestCase { + + private ClockManager mClockManager; + private LeakCheck mLeakCheck; + private FakeExtensionController mFakeExtensionController; + private DockManagerFake mFakeDockManager; + @Mock ClockManager.ClockChangedListener mMockListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mLeakCheck = new LeakCheck(); + mFakeExtensionController = new FakeExtensionController(mLeakCheck); + mFakeDockManager = new DockManagerFake(); + mClockManager = new ClockManager(getContext(), mFakeExtensionController, + mFakeDockManager); + mClockManager.addOnClockChangedListener(mMockListener); + } + + @After + public void tearDown() { + mClockManager.removeOnClockChangedListener(mMockListener); + } + + @Test + public void dockEvent() { + mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED); + assertThat(mClockManager.isDocked()).isTrue(); + } + + @Test + public void undockEvent() { + mFakeDockManager.setDockEvent(DockManager.STATE_NONE); + assertThat(mClockManager.isDocked()).isFalse(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java new file mode 100644 index 000000000000..1a3b198ac0d6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 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.keyguard.clock; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.LayoutInflater; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ClockPlugin; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public final class DefaultClockSupplierTest extends SysuiTestCase { + + private static final String BUBBLE_CLOCK = BubbleClockController.class.getName(); + private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class; + + private DefaultClockSupplier mDefaultClockSupplier; + @Mock SettingsWrapper mMockSettingsWrapper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mDefaultClockSupplier = new DefaultClockSupplier(mMockSettingsWrapper, + LayoutInflater.from(getContext())); + } + + @Test + public void get_default() { + // GIVEN that settings doesn't contain any values + when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(null); + when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(null); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the result is null, indicated the default clock face should be used. + assertThat(plugin).isNull(); + } + + @Test + public void get_customClock() { + // GIVEN that settings is set to the bubble clock face + when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the plugin is the bubble clock face. + assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS); + } + + @Test + public void get_badSettingsValue() { + // GIVEN that settings contains a value that doesn't correspond to a + // custom clock face. + when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn("bad value"); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the result is null. + assertThat(plugin).isNull(); + } + + @Test + public void get_dockedDefault() { + // GIVEN docked + mDefaultClockSupplier.setDocked(true); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the result is null, indicating the default clock face. + assertThat(plugin).isNull(); + } + + @Test + public void get_dockedCustomClock() { + // GIVEN docked and settings is set to the bubble clock face + mDefaultClockSupplier.setDocked(true); + when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(BUBBLE_CLOCK); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the plugin is the bubble clock face. + assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS); + } + + @Test + public void get_badDockedSettingsValue() { + // GIVEN docked and settings contains a value that doesn't correspond to + // an available clock face. + mDefaultClockSupplier.setDocked(true); + when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value"); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the result is null. + assertThat(plugin).isNull(); + } + + @Test + public void get_badDockedSettingsFallback() { + // GIVEN docked and settings contains a value that doesn't correspond to + // an available clock face, but locked screen settings is set to bubble + // clock. + mDefaultClockSupplier.setDocked(true); + when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value"); + when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK); + // WHEN get is called + ClockPlugin plugin = mDefaultClockSupplier.get(); + // THEN the plugin is the bubble clock face. + assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS); + } +} diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 3c910696ba60..d9adec85d40e 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6975,6 +6975,23 @@ message MetricsEvent { // formerly: histogram system_cost_for_smart_sharing FIELD_TIME_TO_APP_TARGETS = 1653; + // Open: Settings > Panel for Internet Connectivity + PANEL_INTERNET_CONNECTIVITY = 1654; + + // Open: Settings > Panel for Volume + PANEL_VOLUME = 1655; + + // Open: Settings > Panel for NFC + PANEL_NFC = 1656; + + // Open: Settings > Panel for Media Output + PANEL_MEDIA_OUTPUT = 1657; + + // ACTION: An interaction with a Slice or other component in the Panel. + // CATEGORY: SETTINGS + // OS: Q + ACTION_PANEL_INTERACTION = 1658; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 4834ce0da9b3..3479e18b97c5 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -67,6 +67,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.IInterface; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -109,6 +110,7 @@ import com.android.server.location.LocationRequestStatistics.PackageProviderKey; import com.android.server.location.LocationRequestStatistics.PackageStatistics; import com.android.server.location.MockProvider; import com.android.server.location.PassiveProvider; +import com.android.server.location.RemoteListenerHelper; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -121,6 +123,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.function.Consumer; +import java.util.function.Function; /** * The service class that manages LocationProviders and issues location @@ -225,11 +229,14 @@ public class LocationManagerService extends ILocationManager.Stub { private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>(); @GuardedBy("mLock") - private final ArrayMap<IBinder, CallerIdentity> mGnssMeasurementsListeners = new ArrayMap<>(); - + private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>> + mGnssMeasurementsListeners = new ArrayMap<>(); @GuardedBy("mLock") - private final ArrayMap<IBinder, CallerIdentity> + private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>> mGnssNavigationMessageListeners = new ArrayMap<>(); + @GuardedBy("mLock") + private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>> + mGnssStatusListeners = new ArrayMap<>(); // current active user on the device - other users are denied location data private int mCurrentUserId = UserHandle.USER_SYSTEM; @@ -243,7 +250,7 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private IBatchedLocationCallback mGnssBatchingCallback; @GuardedBy("mLock") - private LinkedCallback mGnssBatchingDeathCallback; + private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback; @GuardedBy("mLock") private boolean mGnssBatchingInProgress = false; @@ -485,7 +492,7 @@ public class LocationManagerService extends ILocationManager.Stub { && record.mIsForegroundUid != foreground) { if (D) { Log.d(TAG, "request from uid " + uid + " is now " - + (foreground ? "foreground" : "background)")); + + foregroundAsString(foreground)); } record.updateForeground(foreground); @@ -499,44 +506,48 @@ public class LocationManagerService extends ILocationManager.Stub { applyRequirementsLocked(provider); } - for (Entry<IBinder, CallerIdentity> entry : mGnssMeasurementsListeners.entrySet()) { - CallerIdentity callerIdentity = entry.getValue(); - if (callerIdentity.mUid == uid) { - if (D) { - Log.d(TAG, "gnss measurements listener from uid " + uid - + " is now " + (foreground ? "foreground" : "background)")); - } - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssMeasurementsProvider.addListener( - IGnssMeasurementsListener.Stub.asInterface(entry.getKey()), - callerIdentity); - } else { - mGnssMeasurementsProvider.removeListener( - IGnssMeasurementsListener.Stub.asInterface(entry.getKey())); - } + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssMeasurementsListeners, + mGnssMeasurementsProvider, IGnssMeasurementsListener.Stub::asInterface, + uid, foreground); + + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssNavigationMessageListeners, + mGnssNavigationMessageProvider, IGnssNavigationMessageListener.Stub::asInterface, + uid, foreground); + + updateGnssDataProviderOnUidImportanceChangedLocked(mGnssStatusListeners, + mGnssStatusProvider, IGnssStatusListener.Stub::asInterface, uid, foreground); + } + + @GuardedBy("mLock") + private <TListener extends IInterface> void updateGnssDataProviderOnUidImportanceChangedLocked( + ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners, + RemoteListenerHelper<TListener> gnssDataProvider, + Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground) { + for (Entry<IBinder, ? extends LinkedListenerBase> entry : gnssDataListeners.entrySet()) { + LinkedListenerBase linkedListener = entry.getValue(); + CallerIdentity callerIdentity = linkedListener.mCallerIdentity; + if (callerIdentity.mUid != uid) { + continue; } - } - for (Entry<IBinder, CallerIdentity> entry : mGnssNavigationMessageListeners.entrySet()) { - CallerIdentity callerIdentity = entry.getValue(); - if (callerIdentity.mUid == uid) { - if (D) { - Log.d(TAG, "gnss navigation message listener from uid " - + uid + " is now " - + (foreground ? "foreground" : "background)")); - } - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssNavigationMessageProvider.addListener( - IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()), - callerIdentity); - } else { - mGnssNavigationMessageProvider.removeListener( - IGnssNavigationMessageListener.Stub.asInterface(entry.getKey())); - } + if (D) { + Log.d(TAG, linkedListener.mListenerName + " from uid " + + uid + " is now " + foregroundAsString(foreground)); + } + + TListener listener = mapBinderToListener.apply(entry.getKey()); + if (foreground || isThrottlingExemptLocked(callerIdentity)) { + gnssDataProvider.addListener(listener, callerIdentity); + } else { + gnssDataProvider.removeListener(listener); } } } + private static String foregroundAsString(boolean foreground) { + return foreground ? "foreground" : "background"; + } + private static boolean isImportanceForeground(int importance) { return importance <= FOREGROUND_IMPORTANCE_CUTOFF; } @@ -1218,9 +1229,8 @@ public class LocationManagerService extends ILocationManager.Stub { * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. */ - private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { + private final class Receiver extends LinkedListenerBase implements PendingIntent.OnFinished { private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000; - final CallerIdentity mCallerIdentity; private final int mAllowedResolutionLevel; // resolution level allowed to receiver private final ILocationListener mListener; @@ -1240,6 +1250,7 @@ public class LocationManagerService extends ILocationManager.Stub { private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) { + super(new CallerIdentity(uid, pid, packageName), "LocationListener"); mListener = listener; mPendingIntent = intent; if (listener != null) { @@ -1248,7 +1259,6 @@ public class LocationManagerService extends ILocationManager.Stub { mKey = intent; } mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid); - mCallerIdentity = new CallerIdentity(uid, pid, packageName); if (workSource != null && workSource.isEmpty()) { workSource = null; } @@ -1486,7 +1496,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void binderDied() { - if (D) Log.d(TAG, "Location listener died"); + if (D) Log.d(TAG, "Remote " + mListenerName + " died."); synchronized (mLock) { removeUpdatesLocked(this); @@ -1617,53 +1627,59 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); synchronized (mLock) { mGnssBatchingCallback = callback; - mGnssBatchingDeathCallback = new LinkedCallback(callback); - try { - callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */); - } catch (RemoteException e) { - // if the remote process registering the listener is already dead, just swallow the - // exception and return - Log.e(TAG, "Remote listener already died.", e); + mGnssBatchingDeathCallback = new LinkedListener<>(callback, + "BatchedLocationCallback", callerIdentity, + (IBatchedLocationCallback listener) -> { + stopGnssBatch(); + removeGnssBatchingCallback(); + }); + if (!linkToListenerDeathNotificationLocked(callback.asBinder(), + mGnssBatchingDeathCallback)) { return false; } - return true; } } - private class LinkedCallback implements IBinder.DeathRecipient { - private final IBatchedLocationCallback mCallback; + private abstract static class LinkedListenerBase implements IBinder.DeathRecipient { + protected final CallerIdentity mCallerIdentity; + protected final String mListenerName; - private LinkedCallback(@NonNull IBatchedLocationCallback callback) { - mCallback = callback; + private LinkedListenerBase(@NonNull CallerIdentity callerIdentity, + @NonNull String listenerName) { + mCallerIdentity = callerIdentity; + mListenerName = listenerName; } + } + + private static class LinkedListener<TListener> extends LinkedListenerBase { + private final TListener mListener; + private final Consumer<TListener> mBinderDeathCallback; - @NonNull - public IBatchedLocationCallback getUnderlyingListener() { - return mCallback; + private LinkedListener(@NonNull TListener listener, String listenerName, + @NonNull CallerIdentity callerIdentity, + @NonNull Consumer<TListener> binderDeathCallback) { + super(callerIdentity, listenerName); + mListener = listener; + mBinderDeathCallback = binderDeathCallback; } @Override public void binderDied() { - Log.d(TAG, "Remote Batching Callback died: " + mCallback); - stopGnssBatch(); - removeGnssBatchingCallback(); + if (D) Log.d(TAG, "Remote " + mListenerName + " died."); + mBinderDeathCallback.accept(mListener); } } @Override public void removeGnssBatchingCallback() { synchronized (mLock) { - try { - mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback, - 0 /* flags */); - } catch (NoSuchElementException e) { - // if the death callback isn't connected (it should be...), log error, swallow the - // exception and return - Log.e(TAG, "Couldn't unlink death callback.", e); - } + unlinkFromListenerDeathNotificationLocked(mGnssBatchingCallback.asBinder(), + mGnssBatchingDeathCallback); mGnssBatchingCallback = null; mGnssBatchingDeathCallback = null; } @@ -2264,10 +2280,8 @@ public class LocationManagerService extends ILocationManager.Stub { if (receiver == null) { receiver = new Receiver(listener, null, pid, uid, packageName, workSource, hideFromAppOps); - try { - receiver.getListener().asBinder().linkToDeath(receiver, 0); - } catch (RemoteException e) { - Slog.e(TAG, "linkToDeath failed:", e); + if (!linkToListenerDeathNotificationLocked(receiver.getListener().asBinder(), + receiver)) { return null; } mReceivers.put(binder, receiver); @@ -2482,7 +2496,8 @@ public class LocationManagerService extends ILocationManager.Stub { if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { - receiver.getListener().asBinder().unlinkToDeath(receiver, 0); + unlinkFromListenerDeathNotificationLocked(receiver.getListener().asBinder(), + receiver); receiver.clearPendingBroadcastsLocked(); } @@ -2694,18 +2709,52 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) { + public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) { if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) { return false; } - return mGnssStatusProvider.addListener(callback, new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName)); + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener<IGnssStatusListener> linkedListener = new LinkedListener<>(listener, + "GnssStatusListener", callerIdentity, this::unregisterGnssStatusCallback); + IBinder binder = listener.asBinder(); + synchronized (mLock) { + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } + + mGnssStatusListeners.put(binder, linkedListener); + long identity = Binder.clearCallingIdentity(); + try { + if (isThrottlingExemptLocked(callerIdentity) + || isImportanceForeground( + mActivityManager.getPackageImportance(packageName))) { + mGnssStatusProvider.addListener(listener, callerIdentity); + } + return true; + } finally { + Binder.restoreCallingIdentity(identity); + } + } } @Override - public void unregisterGnssStatusCallback(IGnssStatusListener callback) { - mGnssStatusProvider.removeListener(callback); + public void unregisterGnssStatusCallback(IGnssStatusListener listener) { + if (mGnssStatusProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener<IGnssStatusListener> linkedListener = + mGnssStatusListeners.remove(binder); + if (linkedListener == null) { + return; + } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssStatusProvider.removeListener(listener); + } } @Override @@ -2715,22 +2764,75 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener<IGnssMeasurementsListener> linkedListener = new LinkedListener<>(listener, + "GnssMeasurementsListener", callerIdentity, this::removeGnssMeasurementsListener); + IBinder binder = listener.asBinder(); synchronized (mLock) { - CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName); - mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity); + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } + + mGnssMeasurementsListeners.put(binder, linkedListener); long identity = Binder.clearCallingIdentity(); try { if (isThrottlingExemptLocked(callerIdentity) || isImportanceForeground( mActivityManager.getPackageImportance(packageName))) { - return mGnssMeasurementsProvider.addListener(listener, callerIdentity); + mGnssMeasurementsProvider.addListener(listener, callerIdentity); } + return true; } finally { Binder.restoreCallingIdentity(identity); } + } + } + + @Override + public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { + if (mGnssMeasurementsProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener<IGnssMeasurementsListener> linkedListener = + mGnssMeasurementsListeners.remove(binder); + if (linkedListener == null) { + return; + } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssMeasurementsProvider.removeListener(listener); + } + } + + private boolean linkToListenerDeathNotificationLocked(IBinder binder, + LinkedListenerBase linkedListener) { + try { + binder.linkToDeath(linkedListener, 0 /* flags */); + return true; + } catch (RemoteException e) { + // if the remote process registering the listener is already dead, just swallow the + // exception and return + Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", + e); + return false; + } + } + + private boolean unlinkFromListenerDeathNotificationLocked(IBinder binder, + LinkedListenerBase linkedListener) { + try { + binder.unlinkToDeath(linkedListener, 0 /* flags */); return true; + } catch (NoSuchElementException e) { + // if the death callback isn't connected (it should be...), log error, + // swallow the exception and return + Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", + e); + return false; } } @@ -2759,52 +2861,53 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { - if (mGnssMeasurementsProvider == null) { - return; - } - - synchronized (mLock) { - mGnssMeasurementsListeners.remove(listener.asBinder()); - mGnssMeasurementsProvider.removeListener(listener); - } - } - - @Override public boolean addGnssNavigationMessageListener( - IGnssNavigationMessageListener listener, - String packageName) { + IGnssNavigationMessageListener listener, String packageName) { if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) { return false; } + CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), + Binder.getCallingPid(), packageName); + LinkedListener<IGnssNavigationMessageListener> linkedListener = + new LinkedListener<>(listener, "GnssNavigationMessageListener", callerIdentity, + this::removeGnssNavigationMessageListener); + IBinder binder = listener.asBinder(); synchronized (mLock) { - CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), - Binder.getCallingPid(), packageName); + if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) { + return false; + } - mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity); + mGnssNavigationMessageListeners.put(binder, linkedListener); long identity = Binder.clearCallingIdentity(); try { if (isThrottlingExemptLocked(callerIdentity) || isImportanceForeground( mActivityManager.getPackageImportance(packageName))) { - return mGnssNavigationMessageProvider.addListener(listener, callerIdentity); + mGnssNavigationMessageProvider.addListener(listener, callerIdentity); } + return true; } finally { Binder.restoreCallingIdentity(identity); } - - return true; } } @Override public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) { - if (mGnssNavigationMessageProvider != null) { - synchronized (mLock) { - mGnssNavigationMessageListeners.remove(listener.asBinder()); - mGnssNavigationMessageProvider.removeListener(listener); + if (mGnssNavigationMessageProvider == null) { + return; + } + + IBinder binder = listener.asBinder(); + synchronized (mLock) { + LinkedListener<IGnssNavigationMessageListener> linkedListener = + mGnssNavigationMessageListeners.remove(binder); + if (linkedListener == null) { + return; } + unlinkFromListenerDeathNotificationLocked(binder, linkedListener); + mGnssNavigationMessageProvider.removeListener(listener); } } @@ -3368,18 +3471,14 @@ public class LocationManagerService extends ILocationManager.Stub { pw.println(" " + record); } } + pw.println(" Active GnssMeasurement Listeners:"); - for (CallerIdentity callerIdentity : mGnssMeasurementsListeners.values()) { - pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " - + callerIdentity.mPackageName + ": " - + isThrottlingExemptLocked(callerIdentity)); - } + dumpGnssDataListenersLocked(pw, mGnssMeasurementsListeners); pw.println(" Active GnssNavigationMessage Listeners:"); - for (CallerIdentity callerIdentity : mGnssNavigationMessageListeners.values()) { - pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " - + callerIdentity.mPackageName + ": " - + isThrottlingExemptLocked(callerIdentity)); - } + dumpGnssDataListenersLocked(pw, mGnssNavigationMessageListeners); + pw.println(" Active GnssStatus Listeners:"); + dumpGnssDataListenersLocked(pw, mGnssStatusListeners); + pw.println(" Historical Records by Provider:"); for (Map.Entry<PackageProviderKey, PackageStatistics> entry : mRequestStatistics.statistics.entrySet()) { @@ -3432,4 +3531,15 @@ public class LocationManagerService extends ILocationManager.Stub { } } } + + @GuardedBy("mLock") + private void dumpGnssDataListenersLocked(PrintWriter pw, + ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners) { + for (LinkedListenerBase listener : gnssDataListeners.values()) { + CallerIdentity callerIdentity = listener.mCallerIdentity; + pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " " + + callerIdentity.mPackageName + ": " + + isThrottlingExemptLocked(callerIdentity)); + } + } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index e7d7434b5dc8..5da281a5ebc3 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -860,7 +860,7 @@ class StorageManagerService extends IStorageManager.Stub } else if (remote == 1) { res = true; } else { - res = false; + res = true; } Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag " @@ -1533,7 +1533,7 @@ class StorageManagerService extends IStorageManager.Stub // Snapshot feature flag used for this boot SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString( - SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false))); + SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true))); mContext = context; mResolver = mContext.getContentResolver(); diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 0bf54392465a..8ffb67a1405c 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -65,6 +65,8 @@ final class CoreSettingsObserver extends ContentObserver { Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class); sGlobalSettingToTypeMap.put( Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class); + sGlobalSettingToTypeMap.put( + Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class); sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class); sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 20933db803b9..560f7a03b20f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -342,7 +342,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { super.disableDevice(initiatedByCec, callback); assertRunOnServiceThread(); - if (!initiatedByCec && mIsActiveSource) { + if (!initiatedByCec && mIsActiveSource && mService.isControlEnabled()) { mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource( mAddress, mService.getPhysicalAddress())); } diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java index f03c99b0272e..aa8a25a36333 100644 --- a/services/core/java/com/android/server/location/RemoteListenerHelper.java +++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java @@ -31,9 +31,11 @@ import java.util.HashMap; import java.util.Map; /** - * A helper class, that handles operations in remote listeners, and tracks for remote process death. + * A helper class that handles operations in remote listeners. + * + * @param <TListener> the type of GNSS data listener. */ -abstract class RemoteListenerHelper<TListener extends IInterface> { +public abstract class RemoteListenerHelper<TListener extends IInterface> { protected static final int RESULT_SUCCESS = 0; protected static final int RESULT_NOT_AVAILABLE = 1; @@ -46,7 +48,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { protected final Handler mHandler; private final String mTag; - private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>(); + private final Map<IBinder, IdentifiedListener> mListenerMap = new HashMap<>(); protected final Context mContext; protected final AppOpsManager mAppOps; @@ -71,24 +73,21 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { return mIsRegistered; } - public boolean addListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + /** + * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}. + */ + public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) { Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener."); IBinder binder = listener.asBinder(); - LinkedListener deathListener = new LinkedListener(listener, callerIdentity); synchronized (mListenerMap) { if (mListenerMap.containsKey(binder)) { // listener already added - return true; - } - try { - binder.linkToDeath(deathListener, 0 /* flags */); - } catch (RemoteException e) { - // if the remote process registering the listener is already death, just swallow the - // exception and return - Log.v(mTag, "Remote listener already died.", e); - return false; + return; } - mListenerMap.put(binder, deathListener); + + IdentifiedListener identifiedListener = new IdentifiedListener(listener, + callerIdentity); + mListenerMap.put(binder, identifiedListener); // update statuses we already know about, starting from the ones that will never change int result; @@ -107,26 +106,23 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { } else { // at this point if the supported flag is not set, the notification will be sent // asynchronously in the future - return true; + return; } - post(deathListener, getHandlerOperation(result)); + post(identifiedListener, getHandlerOperation(result)); } - return true; } + /** + * Remove GNSS data listener {@code listener}. + */ public void removeListener(@NonNull TListener listener) { Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener."); - IBinder binder = listener.asBinder(); - LinkedListener linkedListener; synchronized (mListenerMap) { - linkedListener = mListenerMap.remove(binder); + mListenerMap.remove(listener.asBinder()); if (mListenerMap.isEmpty()) { tryUnregister(); } } - if (linkedListener != null) { - binder.unlinkToDeath(linkedListener, 0 /* flags */); - } } protected abstract boolean isAvailableInPlatform(); @@ -198,14 +194,15 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { } private void foreachUnsafe(ListenerOperation<TListener> operation) { - for (LinkedListener linkedListener : mListenerMap.values()) { - post(linkedListener, operation); + for (IdentifiedListener identifiedListener : mListenerMap.values()) { + post(identifiedListener, operation); } } - private void post(LinkedListener linkedListener, ListenerOperation<TListener> operation) { + private void post(IdentifiedListener identifiedListener, + ListenerOperation<TListener> operation) { if (operation != null) { - mHandler.post(new HandlerRunnable(linkedListener, operation)); + mHandler.post(new HandlerRunnable(identifiedListener, operation)); } } @@ -259,35 +256,31 @@ abstract class RemoteListenerHelper<TListener extends IInterface> { return RESULT_SUCCESS; } - private class LinkedListener implements IBinder.DeathRecipient { + private class IdentifiedListener { private final TListener mListener; private final CallerIdentity mCallerIdentity; - LinkedListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + private IdentifiedListener(@NonNull TListener listener, CallerIdentity callerIdentity) { mListener = listener; mCallerIdentity = callerIdentity; } - - @Override - public void binderDied() { - Log.d(mTag, "Remote Listener died: " + mListener); - removeListener(mListener); - } } private class HandlerRunnable implements Runnable { - private final LinkedListener mLinkedListener; + private final IdentifiedListener mIdentifiedListener; private final ListenerOperation<TListener> mOperation; - HandlerRunnable(LinkedListener linkedListener, ListenerOperation<TListener> operation) { - mLinkedListener = linkedListener; + private HandlerRunnable(IdentifiedListener identifiedListener, + ListenerOperation<TListener> operation) { + mIdentifiedListener = identifiedListener; mOperation = operation; } @Override public void run() { try { - mOperation.execute(mLinkedListener.mListener, mLinkedListener.mCallerIdentity); + mOperation.execute(mIdentifiedListener.mListener, + mIdentifiedListener.mCallerIdentity); } catch (RemoteException e) { Log.v(mTag, "Error in monitored listener.", e); } diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java new file mode 100644 index 000000000000..dac4b6ff39c3 --- /dev/null +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2019 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.s + */ + +package com.android.server.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.apex.ApexInfo; +import android.apex.ApexInfoList; +import android.apex.ApexSessionInfo; +import android.apex.IApexService; +import android.content.pm.PackageInfo; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; + +import com.android.internal.util.IndentingPrintWriter; + +import java.io.File; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * ApexManager class handles communications with the apex service to perform operation and queries, + * as well as providing caching to avoid unnecessary calls to the service. + */ +class ApexManager { + static final String TAG = "ApexManager"; + private final IApexService mApexService; + private final Map<String, PackageInfo> mActivePackagesCache; + + ApexManager() { + mApexService = IApexService.Stub.asInterface( + ServiceManager.getService("apexservice")); + mActivePackagesCache = populateActivePackagesCache(); + } + + @NonNull + private Map<String, PackageInfo> populateActivePackagesCache() { + try { + List<PackageInfo> list = new ArrayList<>(); + final ApexInfo[] activePkgs = mApexService.getActivePackages(); + for (ApexInfo ai : activePkgs) { + // If the device is using flattened APEX, don't report any APEX + // packages since they won't be managed or updated by PackageManager. + if ((new File(ai.packagePath)).isDirectory()) { + break; + } + try { + list.add(PackageParser.generatePackageInfoFromApex( + new File(ai.packagePath), true /* collect certs */)); + } catch (PackageParserException pe) { + throw new IllegalStateException("Unable to parse: " + ai, pe); + } + } + return list.stream().collect(Collectors.toMap(p -> p.packageName, Function.identity())); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); + throw new RuntimeException(re); + } + } + + /** + * Retrieves information about an active APEX package. + * + * @param packageName the package name to look for. Note that this is the package name reported + * in the APK container manifest (i.e. AndroidManifest.xml), which might + * differ from the one reported in the APEX manifest (i.e. + * apex_manifest.json). + * @return a PackageInfo object with the information about the package, or null if the package + * is not found. + */ + @Nullable PackageInfo getActivePackage(String packageName) { + return mActivePackagesCache.get(packageName); + } + + /** + * Retrieves information about all active APEX packages. + * + * @return a Collection of PackageInfo object, each one containing information about a different + * active package. + */ + Collection<PackageInfo> getActivePackages() { + return mActivePackagesCache.values(); + } + + /** + * Retrieves information about an apexd staged session i.e. the internal state used by apexd to + * track the different states of a session. + * + * @param sessionId the identifier of the session. + * @return an ApexSessionInfo object, or null if the session is not known. + */ + @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { + try { + ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); + if (apexSessionInfo.isUnknown) { + return null; + } + return apexSessionInfo; + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + /** + * Submit a staged session to apex service. This causes the apex service to perform some initial + * verification and accept or reject the session. Submitting a session successfully is not + * enough for it to be activated at the next boot, the caller needs to call + * {@link #markStagedSessionReady(int)}. + * + * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. + * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain + * an array of identifiers of all the child sessions. Otherwise it should + * be an empty array. + * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller + * and will be filled with a list of {@link ApexInfo} objects, each of which + * contains metadata about one of the packages being submitted as part of + * the session. + * @return whether the submission of the session was successful. + */ + boolean submitStagedSession( + int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) { + try { + return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + /** + * Mark a staged session previously submitted using {@cde submitStagedSession} as ready to be + * applied at next reboot. + * + * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready. + * @return true upon success, false if the session is unknown. + */ + boolean markStagedSessionReady(int sessionId) { + try { + return mApexService.markStagedSessionReady(sessionId); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + throw new RuntimeException(re); + } + } + + /** + * Dumps various state information to the provided {@link PrintWriter} object. + * + * @param pw the {@link PrintWriter} object to send information to. + * @param packageName a {@link String} containing a package name, or {@code null}. If set, only + * information about that specific package will be dumped. + */ + void dump(PrintWriter pw, @Nullable String packageName) { + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); + ipw.println(); + ipw.println("Active APEX packages:"); + ipw.increaseIndent(); + try { + populateActivePackagesCache(); + for (PackageInfo pi : mActivePackagesCache.values()) { + if (packageName != null && !packageName.equals(pi.packageName)) { + continue; + } + ipw.println(pi.packageName); + ipw.increaseIndent(); + ipw.println("Version: " + pi.versionCode); + ipw.println("Path: " + pi.applicationInfo.sourceDir); + ipw.decreaseIndent(); + } + ipw.decreaseIndent(); + ipw.println(); + ipw.println("APEX session state:"); + ipw.increaseIndent(); + final ApexSessionInfo[] sessions = mApexService.getSessions(); + for (ApexSessionInfo si : sessions) { + ipw.println("Session ID: " + Integer.toString(si.sessionId)); + ipw.increaseIndent(); + if (si.isUnknown) { + ipw.println("State: UNKNOWN"); + } else if (si.isVerified) { + ipw.println("State: VERIFIED"); + } else if (si.isStaged) { + ipw.println("State: STAGED"); + } else if (si.isActivated) { + ipw.println("State: ACTIVATED"); + } else if (si.isActivationPendingRetry) { + ipw.println("State: ACTIVATION PENDING RETRY"); + } else if (si.isActivationFailed) { + ipw.println("State: ACTIVATION FAILED"); + } + ipw.decreaseIndent(); + } + ipw.decreaseIndent(); + } catch (RemoteException e) { + ipw.println("Couldn't communicate with apexd."); + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index f6bd2a95a4a3..86083494f3d6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -186,7 +186,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } }; - public PackageInstallerService(Context context, PackageManagerService pm) { + public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) { mContext = context; mPm = pm; mPermissionManager = LocalServices.getService(PermissionManagerInternal.class); @@ -204,7 +204,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions"); mSessionsDir.mkdirs(); - mStagingManager = new StagingManager(pm, this); + mStagingManager = new StagingManager(pm, this, am); } private void setBootCompleted() { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 310457664f4f..8c00380b82b1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -119,9 +119,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.apex.ApexInfo; -import android.apex.ApexSessionInfo; -import android.apex.IApexService; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppDetailsActivity; @@ -734,10 +731,10 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>(); - private PackageManager mPackageManager; - private final ModuleInfoProvider mModuleInfoProvider; + private final ApexManager mApexManager; + class PackageParserCallback implements PackageParser.Callback { @Override public final boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); @@ -3075,7 +3072,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - mInstallerService = new PackageInstallerService(context, this); + mApexManager = new ApexManager(); + mInstallerService = new PackageInstallerService(context, this, mApexManager); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -3935,27 +3933,7 @@ public class PackageManagerService extends IPackageManager.Stub } // if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) { - //TODO(b/123052859) Don't do file operations every time there is a query. - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - if (apex != null) { - try { - final ApexInfo activePkg = apex.getActivePackage(packageName); - if (activePkg != null && !TextUtils.isEmpty(activePkg.packagePath)) { - try { - return PackageParser.generatePackageInfoFromApex( - new File(activePkg.packagePath), true /* collect certs */); - } catch (PackageParserException pe) { - Log.e(TAG, "Unable to parse package at " - + activePkg.packagePath, pe); - } - } - } catch (RemoteException e) { - Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString()); - } - } else { - Log.e(TAG, "Unable to connect to apexservice for querying packages."); - } + return mApexManager.getActivePackage(packageName); } } return null; @@ -7852,25 +7830,7 @@ public class PackageManagerService extends IPackageManager.Stub if (listApex) { // TODO(b/119767311): include uninstalled/inactive APEX if // MATCH_UNINSTALLED_PACKAGES is set. - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - if (apex != null) { - try { - final ApexInfo[] activePkgs = apex.getActivePackages(); - for (ApexInfo ai : activePkgs) { - try { - list.add(PackageParser.generatePackageInfoFromApex( - new File(ai.packagePath), true /* collect certs */)); - } catch (PackageParserException pe) { - throw new IllegalStateException("Unable to parse: " + ai, pe); - } - } - } catch (RemoteException e) { - Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString()); - } - } else { - Log.e(TAG, "Unable to connect to apexservice for querying packages."); - } + list.addAll(mApexManager.getActivePackages()); } return new ParceledListSlice<>(list); } @@ -21325,51 +21285,7 @@ public class PackageManagerService extends IPackageManager.Stub } if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) { - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); - ipw.println(); - ipw.println("Active APEX packages:"); - ipw.increaseIndent(); - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - try { - final ApexInfo[] activeApexes = apex.getActivePackages(); - for (ApexInfo ai : activeApexes) { - if (packageName != null && !packageName.equals(ai.packageName)) { - continue; - } - ipw.println(ai.packageName); - ipw.increaseIndent(); - ipw.println("Version: " + Long.toString(ai.versionCode)); - ipw.println("Path: " + ai.packagePath); - ipw.decreaseIndent(); - } - ipw.decreaseIndent(); - ipw.println(); - ipw.println("APEX session state:"); - ipw.increaseIndent(); - final ApexSessionInfo[] sessions = apex.getSessions(); - for (ApexSessionInfo si : sessions) { - ipw.println("Session ID: " + Integer.toString(si.sessionId)); - ipw.increaseIndent(); - if (si.isUnknown) { - ipw.println("State: UNKNOWN"); - } else if (si.isVerified) { - ipw.println("State: VERIFIED"); - } else if (si.isStaged) { - ipw.println("State: STAGED"); - } else if (si.isActivated) { - ipw.println("State: ACTIVATED"); - } else if (si.isActivationPendingRetry) { - ipw.println("State: ACTIVATION PENDING RETRY"); - } else if (si.isActivationFailed) { - ipw.println("State: ACTIVATION FAILED"); - } - ipw.decreaseIndent(); - } - ipw.decreaseIndent(); - } catch (RemoteException e) { - ipw.println("Couldn't communicate with apexd."); - } + mApexManager.dump(pw, packageName); } } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index fa8360b1e5ba..30c2281b07f1 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -20,12 +20,12 @@ import android.annotation.NonNull; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; -import android.apex.IApexService; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; @@ -41,7 +41,6 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; -import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; import android.util.apk.ApkSignatureVerifier; @@ -68,14 +67,16 @@ public class StagingManager { private final PackageInstallerService mPi; private final PackageManagerService mPm; + private final ApexManager mApexManager; private final Handler mBgHandler; @GuardedBy("mStagedSessions") private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); - StagingManager(PackageManagerService pm, PackageInstallerService pi) { + StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am) { mPm = pm; mPi = pi; + mApexManager = am; mBgHandler = BackgroundThread.getHandler(); } @@ -100,7 +101,7 @@ public class StagingManager { return new ParceledListSlice<>(result); } - private static boolean validateApexSignature(String apexPath, String packageName) { + private boolean validateApexSignature(String apexPath, String packageName) { final SigningDetails signingDetails; try { signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); @@ -109,17 +110,9 @@ public class StagingManager { return false; } - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - final ApexInfo apexInfo; - try { - apexInfo = apex.getActivePackage(packageName); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact APEXD", re); - return false; - } + final PackageInfo packageInfo = mApexManager.getActivePackage(packageName); - if (apexInfo == null || TextUtils.isEmpty(apexInfo.packageName)) { + if (packageInfo == null) { // TODO: What is the right thing to do here ? This implies there's no active package // with the given name. This should never be the case in production (where we only // accept updates to existing APEXes) but may be required for testing. @@ -129,9 +122,10 @@ public class StagingManager { final SigningDetails existingSigningDetails; try { existingSigningDetails = ApkSignatureVerifier.verify( - apexInfo.packagePath, SignatureSchemeVersion.JAR); + packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR); } catch (PackageParserException e) { - Slog.e(TAG, "Unable to parse APEX package: " + apexInfo.packagePath, e); + Slog.e(TAG, "Unable to parse APEX package: " + + packageInfo.applicationInfo.sourceDir, e); return false; } @@ -143,10 +137,10 @@ public class StagingManager { return false; } - private static boolean submitSessionToApexService(@NonNull PackageInstallerSession session, - List<PackageInstallerSession> childSessions, - ApexInfoList apexInfoList) { - return sendSubmitStagedSessionRequest( + private boolean submitSessionToApexService(@NonNull PackageInstallerSession session, + List<PackageInstallerSession> childSessions, + ApexInfoList apexInfoList) { + return mApexManager.submitStagedSession( session.sessionId, childSessions != null ? childSessions.stream().mapToInt(s -> s.sessionId).toArray() : @@ -154,33 +148,6 @@ public class StagingManager { apexInfoList); } - private static boolean sendSubmitStagedSessionRequest( - int sessionId, int[] childSessionIds, ApexInfoList apexInfoList) { - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - boolean success; - try { - success = apex.submitStagedSession(sessionId, childSessionIds, apexInfoList); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - return false; - } - return success; - } - - private static boolean sendMarkStagedSessionReadyRequest(int sessionId) { - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - boolean success; - try { - success = apex.markStagedSessionReady(sessionId); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - return false; - } - return success; - } - private static boolean isApexSession(@NonNull PackageInstallerSession session) { return (session.params.installFlags & PackageManager.INSTALL_APEX) != 0; } @@ -260,7 +227,7 @@ public class StagingManager { } session.setStagedSessionReady(); - if (!sendMarkStagedSessionReadyRequest(session.sessionId)) { + if (!mApexManager.markStagedSessionReady(session.sessionId)) { session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "APEX staging failed, check logcat messages from apexd for more " + "details."); @@ -284,16 +251,12 @@ public class StagingManager { private void resumeSession(@NonNull PackageInstallerSession session) { if (sessionContainsApex(session)) { - // Check with apexservice whether the apex - // packages have been activated. - final IApexService apex = IApexService.Stub.asInterface( - ServiceManager.getService("apexservice")); - ApexSessionInfo apexSessionInfo; - try { - apexSessionInfo = apex.getStagedSessionInfo(session.sessionId); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to contact apexservice", re); - // TODO should we retry here? Mark the session as failed? + // Check with apexservice whether the apex packages have been activated. + ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId); + if (apexSessionInfo == null) { + session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "apexd did not know anything about a staged session supposed to be" + + "activated"); return; } if (apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown) { @@ -323,8 +286,8 @@ public class StagingManager { // The APEX part of the session is activated, proceed with the installation of APKs. if (!installApksInSession(session)) { session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - "APEX activation failed. Check logcat messages from apexd for " - + "more information."); + "Staged installation of APKs failed. Check logcat messages for" + + "more information."); return; } session.setStagedSessionApplied(); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index dd2cda20e0f1..0aa6051d67ff 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -1169,7 +1169,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { BinderCallsStatsService.Internal binderStats = LocalServices.getService(BinderCallsStatsService.Internal.class); if (binderStats == null) { - return; + throw new IllegalStateException("binderStats is null"); } List<ExportedCallStat> callStats = binderStats.getExportedCallStats(); @@ -1200,7 +1200,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { BinderCallsStatsService.Internal binderStats = LocalServices.getService(BinderCallsStatsService.Internal.class); if (binderStats == null) { - return; + throw new IllegalStateException("binderStats is null"); } ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats(); @@ -1218,7 +1218,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { List<StatsLogEventWrapper> pulledData) { LooperStats looperStats = LocalServices.getService(LooperStats.class); if (looperStats == null) { - return; + throw new IllegalStateException("looperStats null"); } List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); @@ -1689,18 +1689,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullCpuTimePerThreadFreq(int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { if (this.mKernelCpuThreadReader == null) { - return; + throw new IllegalStateException("mKernelCpuThreadReader is null"); } ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages = this.mKernelCpuThreadReader.getProcessCpuUsageByUids(); if (processCpuUsages == null) { - return; + throw new IllegalStateException("processCpuUsages is null"); } int[] cpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz(); if (cpuFrequencies.length > CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES) { - Slog.w(TAG, "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES - + " frequencies, but got " + cpuFrequencies.length); - return; + String message = "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES + + " frequencies, but got " + cpuFrequencies.length; + Slog.w(TAG, message); + throw new IllegalStateException(message); } for (int i = 0; i < processCpuUsages.size(); i++) { KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i); @@ -1709,10 +1710,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { for (int j = 0; j < threadCpuUsages.size(); j++) { KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage = threadCpuUsages.get(j); if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) { - Slog.w(TAG, "Unexpected number of usage times," + String message = "Unexpected number of usage times," + " expected " + cpuFrequencies.length - + " but got " + threadCpuUsage.usageTimesMillis.length); - continue; + + " but got " + threadCpuUsage.usageTimesMillis.length; + Slog.w(TAG, message); + throw new IllegalStateException(message); } StatsLogEventWrapper e = diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index cbc3791264bf..d178c3abc906 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -973,7 +973,10 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement JavaObject& object) { translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object); - SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType))); + SET(CodeType, static_cast<int32_t>(measurement_V2_0->codeType)); + + // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated. + SET(State, static_cast<int32_t>(measurement_V2_0->state)); } jobject GnssMeasurementCallback::translateGnssClock( diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index 6b1b84cd3458..856f08107fd7 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -30,6 +30,7 @@ public final class CellIdentityNr extends CellIdentity { private final int mNrArfcn; private final int mPci; private final int mTac; + private final long mNci; /** * @@ -44,11 +45,12 @@ public final class CellIdentityNr extends CellIdentity { * @hide */ public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr, - String alphal, String alphas) { + long nci, String alphal, String alphas) { super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas); mPci = pci; mTac = tac; mNrArfcn = nrArfcn; + mNci = nci; } /** @@ -62,7 +64,7 @@ public final class CellIdentityNr extends CellIdentity { @Override public int hashCode() { - return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn); + return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn, mNci); } @Override @@ -72,7 +74,17 @@ public final class CellIdentityNr extends CellIdentity { } CellIdentityNr o = (CellIdentityNr) other; - return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn; + return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn + && mNci == o.mNci; + } + + /** + * Get the NR Cell Identity. + * + * @return The NR Cell Identity in range [0, 68719476735] or Long.MAX_VALUE if unknown. + */ + public long getNci() { + return mNci; } /** @@ -122,6 +134,7 @@ public final class CellIdentityNr extends CellIdentity { .append(" mNrArfcn = ").append(mNrArfcn) .append(" mMcc = ").append(mMccStr) .append(" mMnc = ").append(mMncStr) + .append(" mNci = ").append(mNci) .append(" mAlphaLong = ").append(mAlphaLong) .append(" mAlphaShort = ").append(mAlphaShort) .append(" }") @@ -134,6 +147,7 @@ public final class CellIdentityNr extends CellIdentity { dest.writeInt(mPci); dest.writeInt(mTac); dest.writeInt(mNrArfcn); + dest.writeLong(mNci); } /** Construct from Parcel, type has already been processed */ @@ -142,6 +156,7 @@ public final class CellIdentityNr extends CellIdentity { mPci = in.readInt(); mTac = in.readInt(); mNrArfcn = in.readInt(); + mNci = in.readLong(); } /** Implement the Parcelable interface */ |