summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--cmds/statsd/src/atoms.proto36
-rw-r--r--core/java/android/app/Activity.java3
-rw-r--r--core/java/android/os/GraphicsEnvironment.java138
-rw-r--r--core/java/android/os/storage/StorageManager.java2
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/util/MathUtils.java46
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java2
-rw-r--r--core/java/android/widget/Editor.java6
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp6
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp2
-rw-r--r--core/proto/android/app/settings_enums.proto17
-rw-r--r--core/proto/android/hardware/sensor/assist/enums.proto34
-rw-r--r--core/proto/android/providers/settings/global.proto2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java2
-rw-r--r--libs/hwui/FrameMetricsObserver.h2
-rw-r--r--location/java/android/location/GnssMeasurement.java397
-rw-r--r--native/android/libandroid.map.txt1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java132
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java235
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java117
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java101
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java75
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java132
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto17
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java340
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java2
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java73
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java221
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java98
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java83
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java24
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp5
-rw-r--r--telephony/java/android/telephony/CellIdentityNr.java21
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 &amp; 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 &nbsp;(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 */