Merge "Adding tracing for DPC::updatePowerState for tracking its performance"
diff --git a/Android.bp b/Android.bp
index ef25ec2..30b38d3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -326,7 +326,6 @@
"packages/modules/Connectivity/framework/aidl-export",
"packages/modules/Media/apex/aidl/stable",
"hardware/interfaces/graphics/common/aidl",
- "frameworks/native/libs/permission/aidl",
],
},
dxflags: [
@@ -596,7 +595,6 @@
"packages/modules/Connectivity/framework/aidl-export",
"packages/modules/Media/apex/aidl/stable",
"hardware/interfaces/graphics/common/aidl",
- "frameworks/native/libs/permission/aidl",
],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
diff --git a/core/api/current.txt b/core/api/current.txt
index 9ebd118..3efe2ef 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9126,7 +9126,6 @@
method @Nullable public String getAttributionTag();
method @Nullable public android.content.AttributionSource getNext();
method @Nullable public String getPackageName();
- method public int getPid();
method public int getUid();
method public boolean isTrusted(@NonNull android.content.Context);
method @NonNull public static android.content.AttributionSource myAttributionSource();
@@ -9141,7 +9140,6 @@
method @NonNull public android.content.AttributionSource.Builder setAttributionTag(@Nullable String);
method @NonNull public android.content.AttributionSource.Builder setNext(@Nullable android.content.AttributionSource);
method @NonNull public android.content.AttributionSource.Builder setPackageName(@Nullable String);
- method @NonNull public android.content.AttributionSource.Builder setPid(int);
}
public abstract class BroadcastReceiver {
@@ -32007,7 +32005,6 @@
method @Deprecated public static final boolean supportsProcesses();
field public static final int BLUETOOTH_UID = 1002; // 0x3ea
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
- field public static final int INVALID_PID = -1; // 0xffffffff
field public static final int INVALID_UID = -1; // 0xffffffff
field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
field public static final int PHONE_UID = 1001; // 0x3e9
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 610cb94..e890005 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -172,6 +172,7 @@
method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpSinkInfo(int);
method @NonNull public static android.media.BluetoothProfileConnectionInfo createHearingAidInfo(boolean);
method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioInfo(boolean, boolean);
+ method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioOutputInfo(boolean, int);
method public int describeContents();
method public int getProfile();
method public int getVolume();
diff --git a/core/java/android/app/AppOpInfo.java b/core/java/android/app/AppOpInfo.java
new file mode 100644
index 0000000..979c910
--- /dev/null
+++ b/core/java/android/app/AppOpInfo.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 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 android.app;
+
+import static android.app.AppOpsManager.OP_NONE;
+
+import android.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * Information about a particular app op.
+ */
+class AppOpInfo {
+ /**
+ * A unique constant identifying this app op.
+ */
+ public final int code;
+
+ /**
+ * This maps each operation to the operation that serves as the
+ * switch to determine whether it is allowed. Generally this is
+ * a 1:1 mapping, but for some things (like location) that have
+ * multiple low-level operations being tracked that should be
+ * presented to the user as one switch then this can be used to
+ * make them all controlled by the same single operation.
+ */
+ public final int switchCode;
+
+ /**
+ * This maps each operation to the public string constant for it.
+ */
+ public final String name;
+
+ /**
+ * This provides a simple name for each operation to be used
+ * in debug output.
+ */
+ public final String simpleName;
+
+ /**
+ * This optionally maps a permission to an operation. If there
+ * is no permission associated with an operation, it is null.
+ */
+ public final String permission;
+
+ /**
+ * Specifies whether an Op should be restricted by a user restriction.
+ * Each Op should be filled with a restriction string from UserManager or
+ * null to specify it is not affected by any user restriction.
+ */
+ public final String restriction;
+
+ /**
+ * In which cases should an app be allowed to bypass the
+ * {@link AppOpsManager#setUserRestriction user restriction} for a certain app-op.
+ */
+ public final AppOpsManager.RestrictionBypass allowSystemRestrictionBypass;
+
+ /**
+ * This specifies the default mode for each operation.
+ */
+ public final int defaultMode;
+
+ /**
+ * This specifies whether each option is allowed to be reset
+ * when resetting all app preferences. Disable reset for
+ * app ops that are under strong control of some part of the
+ * system (such as OP_WRITE_SMS, which should be allowed only
+ * for whichever app is selected as the current SMS app).
+ */
+ public final boolean disableReset;
+
+ /**
+ * This specifies whether each option is only allowed to be read
+ * by apps with manage appops permission.
+ */
+ public final boolean restrictRead;
+
+ AppOpInfo(int code,
+ int switchCode,
+ @NonNull String name,
+ @NonNull String simpleName,
+ String permission,
+ String restriction,
+ AppOpsManager.RestrictionBypass allowSystemRestrictionBypass,
+ int defaultMode,
+ boolean disableReset,
+ boolean restrictRead) {
+ if (code < OP_NONE) throw new IllegalArgumentException();
+ if (switchCode < OP_NONE) throw new IllegalArgumentException();
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(simpleName);
+ this.code = code;
+ this.switchCode = switchCode;
+ this.name = name;
+ this.simpleName = simpleName;
+ this.permission = permission;
+ this.restriction = restriction;
+ this.allowSystemRestrictionBypass = allowSystemRestrictionBypass;
+ this.defaultMode = defaultMode;
+ this.disableReset = disableReset;
+ this.restrictRead = restrictRead;
+ }
+
+ static class Builder {
+ private int mCode;
+ private int mSwitchCode;
+ private String mName;
+ private String mSimpleName;
+ private String mPermission = null;
+ private String mRestriction = null;
+ private AppOpsManager.RestrictionBypass mAllowSystemRestrictionBypass = null;
+ private int mDefaultMode = AppOpsManager.MODE_DEFAULT;
+ private boolean mDisableReset = false;
+ private boolean mRestrictRead = false;
+
+ Builder(int code, @NonNull String name, @NonNull String simpleName) {
+ if (code < OP_NONE) throw new IllegalArgumentException();
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(simpleName);
+ this.mCode = code;
+ this.mSwitchCode = code;
+ this.mName = name;
+ this.mSimpleName = simpleName;
+ }
+
+ public Builder setCode(int value) {
+ this.mCode = value;
+ return this;
+ }
+
+ public Builder setSwitchCode(int value) {
+ this.mSwitchCode = value;
+ return this;
+ }
+
+ public Builder setName(String value) {
+ this.mName = value;
+ return this;
+ }
+
+ public Builder setSimpleName(String value) {
+ this.mSimpleName = value;
+ return this;
+ }
+
+ public Builder setPermission(String value) {
+ this.mPermission = value;
+ return this;
+ }
+
+ public Builder setRestriction(String value) {
+ this.mRestriction = value;
+ return this;
+ }
+
+ public Builder setAllowSystemRestrictionBypass(
+ AppOpsManager.RestrictionBypass value) {
+ this.mAllowSystemRestrictionBypass = value;
+ return this;
+ }
+
+ public Builder setDefaultMode(int value) {
+ this.mDefaultMode = value;
+ return this;
+ }
+
+ public Builder setDisableReset(boolean value) {
+ this.mDisableReset = value;
+ return this;
+ }
+
+ public Builder setRestrictRead(boolean value) {
+ this.mRestrictRead = value;
+ return this;
+ }
+
+ public AppOpInfo build() {
+ return new AppOpInfo(mCode, mSwitchCode, mName, mSimpleName, mPermission, mRestriction,
+ mAllowSystemRestrictionBypass, mDefaultMode, mDisableReset, mRestrictRead);
+ }
+ }
+}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2f282f7..2a5916d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -867,8 +867,7 @@
// when adding one of these:
// - increment _NUM_OP
// - define an OPSTR_* constant (marked as @SystemApi)
- // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode, sOpDisableReset,
- // sOpRestrictions, sOpAllowSystemRestrictionBypass
+ // - add row to sAppOpInfos
// - add descriptive strings to Settings/res/values/arrays.xml
// - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
@@ -1909,1163 +1908,379 @@
OP_TURN_SCREEN_ON,
};
- /**
- * This maps each operation to the operation that serves as the
- * switch to determine whether it is allowed. Generally this is
- * a 1:1 mapping, but for some things (like location) that have
- * multiple low-level operations being tracked that should be
- * presented to the user as one switch then this can be used to
- * make them all controlled by the same single operation.
- */
- private static int[] sOpToSwitch = new int[] {
- OP_COARSE_LOCATION, // COARSE_LOCATION
- OP_FINE_LOCATION, // FINE_LOCATION
- OP_COARSE_LOCATION, // GPS
- OP_VIBRATE, // VIBRATE
- OP_READ_CONTACTS, // READ_CONTACTS
- OP_WRITE_CONTACTS, // WRITE_CONTACTS
- OP_READ_CALL_LOG, // READ_CALL_LOG
- OP_WRITE_CALL_LOG, // WRITE_CALL_LOG
- OP_READ_CALENDAR, // READ_CALENDAR
- OP_WRITE_CALENDAR, // WRITE_CALENDAR
- OP_COARSE_LOCATION, // WIFI_SCAN
- OP_POST_NOTIFICATION, // POST_NOTIFICATION
- OP_COARSE_LOCATION, // NEIGHBORING_CELLS
- OP_CALL_PHONE, // CALL_PHONE
- OP_READ_SMS, // READ_SMS
- OP_WRITE_SMS, // WRITE_SMS
- OP_RECEIVE_SMS, // RECEIVE_SMS
- OP_RECEIVE_SMS, // RECEIVE_EMERGECY_SMS
- OP_RECEIVE_MMS, // RECEIVE_MMS
- OP_RECEIVE_WAP_PUSH, // RECEIVE_WAP_PUSH
- OP_SEND_SMS, // SEND_SMS
- OP_READ_SMS, // READ_ICC_SMS
- OP_WRITE_SMS, // WRITE_ICC_SMS
- OP_WRITE_SETTINGS, // WRITE_SETTINGS
- OP_SYSTEM_ALERT_WINDOW, // SYSTEM_ALERT_WINDOW
- OP_ACCESS_NOTIFICATIONS, // ACCESS_NOTIFICATIONS
- OP_CAMERA, // CAMERA
- OP_RECORD_AUDIO, // RECORD_AUDIO
- OP_PLAY_AUDIO, // PLAY_AUDIO
- OP_READ_CLIPBOARD, // READ_CLIPBOARD
- OP_WRITE_CLIPBOARD, // WRITE_CLIPBOARD
- OP_TAKE_MEDIA_BUTTONS, // TAKE_MEDIA_BUTTONS
- OP_TAKE_AUDIO_FOCUS, // TAKE_AUDIO_FOCUS
- OP_AUDIO_MASTER_VOLUME, // AUDIO_MASTER_VOLUME
- OP_AUDIO_VOICE_VOLUME, // AUDIO_VOICE_VOLUME
- OP_AUDIO_RING_VOLUME, // AUDIO_RING_VOLUME
- OP_AUDIO_MEDIA_VOLUME, // AUDIO_MEDIA_VOLUME
- OP_AUDIO_ALARM_VOLUME, // AUDIO_ALARM_VOLUME
- OP_AUDIO_NOTIFICATION_VOLUME, // AUDIO_NOTIFICATION_VOLUME
- OP_AUDIO_BLUETOOTH_VOLUME, // AUDIO_BLUETOOTH_VOLUME
- OP_WAKE_LOCK, // WAKE_LOCK
- OP_COARSE_LOCATION, // MONITOR_LOCATION
- OP_COARSE_LOCATION, // MONITOR_HIGH_POWER_LOCATION
- OP_GET_USAGE_STATS, // GET_USAGE_STATS
- OP_MUTE_MICROPHONE, // MUTE_MICROPHONE
- OP_TOAST_WINDOW, // TOAST_WINDOW
- OP_PROJECT_MEDIA, // PROJECT_MEDIA
- OP_ACTIVATE_VPN, // ACTIVATE_VPN
- OP_WRITE_WALLPAPER, // WRITE_WALLPAPER
- OP_ASSIST_STRUCTURE, // ASSIST_STRUCTURE
- OP_ASSIST_SCREENSHOT, // ASSIST_SCREENSHOT
- OP_READ_PHONE_STATE, // READ_PHONE_STATE
- OP_ADD_VOICEMAIL, // ADD_VOICEMAIL
- OP_USE_SIP, // USE_SIP
- OP_PROCESS_OUTGOING_CALLS, // PROCESS_OUTGOING_CALLS
- OP_USE_FINGERPRINT, // USE_FINGERPRINT
- OP_BODY_SENSORS, // BODY_SENSORS
- OP_READ_CELL_BROADCASTS, // READ_CELL_BROADCASTS
- OP_MOCK_LOCATION, // MOCK_LOCATION
- OP_READ_EXTERNAL_STORAGE, // READ_EXTERNAL_STORAGE
- OP_WRITE_EXTERNAL_STORAGE, // WRITE_EXTERNAL_STORAGE
- OP_TURN_SCREEN_ON, // TURN_SCREEN_ON
- OP_GET_ACCOUNTS, // GET_ACCOUNTS
- OP_RUN_IN_BACKGROUND, // RUN_IN_BACKGROUND
- OP_AUDIO_ACCESSIBILITY_VOLUME, // AUDIO_ACCESSIBILITY_VOLUME
- OP_READ_PHONE_NUMBERS, // READ_PHONE_NUMBERS
- OP_REQUEST_INSTALL_PACKAGES, // REQUEST_INSTALL_PACKAGES
- OP_PICTURE_IN_PICTURE, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
- OP_INSTANT_APP_START_FOREGROUND, // INSTANT_APP_START_FOREGROUND
- OP_ANSWER_PHONE_CALLS, // ANSWER_PHONE_CALLS
- OP_RUN_ANY_IN_BACKGROUND, // OP_RUN_ANY_IN_BACKGROUND
- OP_CHANGE_WIFI_STATE, // OP_CHANGE_WIFI_STATE
- OP_REQUEST_DELETE_PACKAGES, // OP_REQUEST_DELETE_PACKAGES
- OP_BIND_ACCESSIBILITY_SERVICE, // OP_BIND_ACCESSIBILITY_SERVICE
- OP_ACCEPT_HANDOVER, // ACCEPT_HANDOVER
- OP_MANAGE_IPSEC_TUNNELS, // MANAGE_IPSEC_HANDOVERS
- OP_START_FOREGROUND, // START_FOREGROUND
- OP_BLUETOOTH_SCAN, // BLUETOOTH_SCAN
- OP_USE_BIOMETRIC, // BIOMETRIC
- OP_ACTIVITY_RECOGNITION, // ACTIVITY_RECOGNITION
- OP_SMS_FINANCIAL_TRANSACTIONS, // SMS_FINANCIAL_TRANSACTIONS
- OP_READ_MEDIA_AUDIO, // READ_MEDIA_AUDIO
- OP_WRITE_MEDIA_AUDIO, // WRITE_MEDIA_AUDIO
- OP_READ_MEDIA_VIDEO, // READ_MEDIA_VIDEO
- OP_WRITE_MEDIA_VIDEO, // WRITE_MEDIA_VIDEO
- OP_READ_MEDIA_IMAGES, // READ_MEDIA_IMAGES
- OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES
- OP_LEGACY_STORAGE, // LEGACY_STORAGE
- OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY
- OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS
- OP_ACCESS_MEDIA_LOCATION, // ACCESS_MEDIA_LOCATION
- OP_QUERY_ALL_PACKAGES, // QUERY_ALL_PACKAGES
- OP_MANAGE_EXTERNAL_STORAGE, // MANAGE_EXTERNAL_STORAGE
- OP_INTERACT_ACROSS_PROFILES, //INTERACT_ACROSS_PROFILES
- OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN
- OP_LOADER_USAGE_STATS, // LOADER_USAGE_STATS
- OP_DEPRECATED_1, // deprecated
- OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
- OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE
- OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE
- OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
- OP_RECORD_AUDIO_HOTWORD, // RECORD_AUDIO_HOTWORD
- OP_MANAGE_ONGOING_CALLS, // MANAGE_ONGOING_CALLS
- OP_MANAGE_CREDENTIALS, // MANAGE_CREDENTIALS
- OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- OP_RECORD_AUDIO_OUTPUT, // RECORD_AUDIO_OUTPUT
- OP_SCHEDULE_EXACT_ALARM, // SCHEDULE_EXACT_ALARM
- OP_FINE_LOCATION, // OP_FINE_LOCATION_SOURCE
- OP_COARSE_LOCATION, // OP_COARSE_LOCATION_SOURCE
- OP_MANAGE_MEDIA, // MANAGE_MEDIA
- OP_BLUETOOTH_CONNECT, // OP_BLUETOOTH_CONNECT
- OP_UWB_RANGING, // OP_UWB_RANGING
- OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION_SOURCE
- OP_BLUETOOTH_ADVERTISE, // OP_BLUETOOTH_ADVERTISE
- OP_RECORD_INCOMING_PHONE_AUDIO, // OP_RECORD_INCOMING_PHONE_AUDIO
- OP_NEARBY_WIFI_DEVICES, // OP_NEARBY_WIFI_DEVICES
- OP_ESTABLISH_VPN_SERVICE, // OP_ESTABLISH_VPN_SERVICE
- OP_ESTABLISH_VPN_MANAGER, // OP_ESTABLISH_VPN_MANAGER
- OP_ACCESS_RESTRICTED_SETTINGS, // OP_ACCESS_RESTRICTED_SETTINGS
- OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, // RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * This maps each operation to the public string constant for it.
- */
- private static String[] sOpToString = new String[]{
- OPSTR_COARSE_LOCATION,
- OPSTR_FINE_LOCATION,
- OPSTR_GPS,
- OPSTR_VIBRATE,
- OPSTR_READ_CONTACTS,
- OPSTR_WRITE_CONTACTS,
- OPSTR_READ_CALL_LOG,
- OPSTR_WRITE_CALL_LOG,
- OPSTR_READ_CALENDAR,
- OPSTR_WRITE_CALENDAR,
- OPSTR_WIFI_SCAN,
- OPSTR_POST_NOTIFICATION,
- OPSTR_NEIGHBORING_CELLS,
- OPSTR_CALL_PHONE,
- OPSTR_READ_SMS,
- OPSTR_WRITE_SMS,
- OPSTR_RECEIVE_SMS,
- OPSTR_RECEIVE_EMERGENCY_BROADCAST,
- OPSTR_RECEIVE_MMS,
- OPSTR_RECEIVE_WAP_PUSH,
- OPSTR_SEND_SMS,
- OPSTR_READ_ICC_SMS,
- OPSTR_WRITE_ICC_SMS,
- OPSTR_WRITE_SETTINGS,
- OPSTR_SYSTEM_ALERT_WINDOW,
- OPSTR_ACCESS_NOTIFICATIONS,
- OPSTR_CAMERA,
- OPSTR_RECORD_AUDIO,
- OPSTR_PLAY_AUDIO,
- OPSTR_READ_CLIPBOARD,
- OPSTR_WRITE_CLIPBOARD,
- OPSTR_TAKE_MEDIA_BUTTONS,
- OPSTR_TAKE_AUDIO_FOCUS,
- OPSTR_AUDIO_MASTER_VOLUME,
- OPSTR_AUDIO_VOICE_VOLUME,
- OPSTR_AUDIO_RING_VOLUME,
- OPSTR_AUDIO_MEDIA_VOLUME,
- OPSTR_AUDIO_ALARM_VOLUME,
- OPSTR_AUDIO_NOTIFICATION_VOLUME,
- OPSTR_AUDIO_BLUETOOTH_VOLUME,
- OPSTR_WAKE_LOCK,
- OPSTR_MONITOR_LOCATION,
- OPSTR_MONITOR_HIGH_POWER_LOCATION,
- OPSTR_GET_USAGE_STATS,
- OPSTR_MUTE_MICROPHONE,
- OPSTR_TOAST_WINDOW,
- OPSTR_PROJECT_MEDIA,
- OPSTR_ACTIVATE_VPN,
- OPSTR_WRITE_WALLPAPER,
- OPSTR_ASSIST_STRUCTURE,
- OPSTR_ASSIST_SCREENSHOT,
- OPSTR_READ_PHONE_STATE,
- OPSTR_ADD_VOICEMAIL,
- OPSTR_USE_SIP,
- OPSTR_PROCESS_OUTGOING_CALLS,
- OPSTR_USE_FINGERPRINT,
- OPSTR_BODY_SENSORS,
- OPSTR_READ_CELL_BROADCASTS,
- OPSTR_MOCK_LOCATION,
- OPSTR_READ_EXTERNAL_STORAGE,
- OPSTR_WRITE_EXTERNAL_STORAGE,
- OPSTR_TURN_SCREEN_ON,
- OPSTR_GET_ACCOUNTS,
- OPSTR_RUN_IN_BACKGROUND,
- OPSTR_AUDIO_ACCESSIBILITY_VOLUME,
- OPSTR_READ_PHONE_NUMBERS,
- OPSTR_REQUEST_INSTALL_PACKAGES,
- OPSTR_PICTURE_IN_PICTURE,
- OPSTR_INSTANT_APP_START_FOREGROUND,
- OPSTR_ANSWER_PHONE_CALLS,
- OPSTR_RUN_ANY_IN_BACKGROUND,
- OPSTR_CHANGE_WIFI_STATE,
- OPSTR_REQUEST_DELETE_PACKAGES,
- OPSTR_BIND_ACCESSIBILITY_SERVICE,
- OPSTR_ACCEPT_HANDOVER,
- OPSTR_MANAGE_IPSEC_TUNNELS,
- OPSTR_START_FOREGROUND,
- OPSTR_BLUETOOTH_SCAN,
- OPSTR_USE_BIOMETRIC,
- OPSTR_ACTIVITY_RECOGNITION,
- OPSTR_SMS_FINANCIAL_TRANSACTIONS,
- OPSTR_READ_MEDIA_AUDIO,
- OPSTR_WRITE_MEDIA_AUDIO,
- OPSTR_READ_MEDIA_VIDEO,
- OPSTR_WRITE_MEDIA_VIDEO,
- OPSTR_READ_MEDIA_IMAGES,
- OPSTR_WRITE_MEDIA_IMAGES,
- OPSTR_LEGACY_STORAGE,
- OPSTR_ACCESS_ACCESSIBILITY,
- OPSTR_READ_DEVICE_IDENTIFIERS,
- OPSTR_ACCESS_MEDIA_LOCATION,
- OPSTR_QUERY_ALL_PACKAGES,
- OPSTR_MANAGE_EXTERNAL_STORAGE,
- OPSTR_INTERACT_ACROSS_PROFILES,
- OPSTR_ACTIVATE_PLATFORM_VPN,
- OPSTR_LOADER_USAGE_STATS,
- "", // deprecated
- OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
- OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
- OPSTR_NO_ISOLATED_STORAGE,
- OPSTR_PHONE_CALL_MICROPHONE,
- OPSTR_PHONE_CALL_CAMERA,
- OPSTR_RECORD_AUDIO_HOTWORD,
- OPSTR_MANAGE_ONGOING_CALLS,
- OPSTR_MANAGE_CREDENTIALS,
- OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
- OPSTR_RECORD_AUDIO_OUTPUT,
- OPSTR_SCHEDULE_EXACT_ALARM,
- OPSTR_FINE_LOCATION_SOURCE,
- OPSTR_COARSE_LOCATION_SOURCE,
- OPSTR_MANAGE_MEDIA,
- OPSTR_BLUETOOTH_CONNECT,
- OPSTR_UWB_RANGING,
- OPSTR_ACTIVITY_RECOGNITION_SOURCE,
- OPSTR_BLUETOOTH_ADVERTISE,
- OPSTR_RECORD_INCOMING_PHONE_AUDIO,
- OPSTR_NEARBY_WIFI_DEVICES,
- OPSTR_ESTABLISH_VPN_SERVICE,
- OPSTR_ESTABLISH_VPN_MANAGER,
- OPSTR_ACCESS_RESTRICTED_SETTINGS,
- OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
- };
-
- /**
- * This provides a simple name for each operation to be used
- * in debug output.
- */
- private static String[] sOpNames = new String[] {
- "COARSE_LOCATION",
- "FINE_LOCATION",
- "GPS",
- "VIBRATE",
- "READ_CONTACTS",
- "WRITE_CONTACTS",
- "READ_CALL_LOG",
- "WRITE_CALL_LOG",
- "READ_CALENDAR",
- "WRITE_CALENDAR",
- "WIFI_SCAN",
- "POST_NOTIFICATION",
- "NEIGHBORING_CELLS",
- "CALL_PHONE",
- "READ_SMS",
- "WRITE_SMS",
- "RECEIVE_SMS",
- "RECEIVE_EMERGECY_SMS",
- "RECEIVE_MMS",
- "RECEIVE_WAP_PUSH",
- "SEND_SMS",
- "READ_ICC_SMS",
- "WRITE_ICC_SMS",
- "WRITE_SETTINGS",
- "SYSTEM_ALERT_WINDOW",
- "ACCESS_NOTIFICATIONS",
- "CAMERA",
- "RECORD_AUDIO",
- "PLAY_AUDIO",
- "READ_CLIPBOARD",
- "WRITE_CLIPBOARD",
- "TAKE_MEDIA_BUTTONS",
- "TAKE_AUDIO_FOCUS",
- "AUDIO_MASTER_VOLUME",
- "AUDIO_VOICE_VOLUME",
- "AUDIO_RING_VOLUME",
- "AUDIO_MEDIA_VOLUME",
- "AUDIO_ALARM_VOLUME",
- "AUDIO_NOTIFICATION_VOLUME",
- "AUDIO_BLUETOOTH_VOLUME",
- "WAKE_LOCK",
- "MONITOR_LOCATION",
- "MONITOR_HIGH_POWER_LOCATION",
- "GET_USAGE_STATS",
- "MUTE_MICROPHONE",
- "TOAST_WINDOW",
- "PROJECT_MEDIA",
- "ACTIVATE_VPN",
- "WRITE_WALLPAPER",
- "ASSIST_STRUCTURE",
- "ASSIST_SCREENSHOT",
- "READ_PHONE_STATE",
- "ADD_VOICEMAIL",
- "USE_SIP",
- "PROCESS_OUTGOING_CALLS",
- "USE_FINGERPRINT",
- "BODY_SENSORS",
- "READ_CELL_BROADCASTS",
- "MOCK_LOCATION",
- "READ_EXTERNAL_STORAGE",
- "WRITE_EXTERNAL_STORAGE",
- "TURN_ON_SCREEN",
- "GET_ACCOUNTS",
- "RUN_IN_BACKGROUND",
- "AUDIO_ACCESSIBILITY_VOLUME",
- "READ_PHONE_NUMBERS",
- "REQUEST_INSTALL_PACKAGES",
- "PICTURE_IN_PICTURE",
- "INSTANT_APP_START_FOREGROUND",
- "ANSWER_PHONE_CALLS",
- "RUN_ANY_IN_BACKGROUND",
- "CHANGE_WIFI_STATE",
- "REQUEST_DELETE_PACKAGES",
- "BIND_ACCESSIBILITY_SERVICE",
- "ACCEPT_HANDOVER",
- "MANAGE_IPSEC_TUNNELS",
- "START_FOREGROUND",
- "BLUETOOTH_SCAN",
- "USE_BIOMETRIC",
- "ACTIVITY_RECOGNITION",
- "SMS_FINANCIAL_TRANSACTIONS",
- "READ_MEDIA_AUDIO",
- "WRITE_MEDIA_AUDIO",
- "READ_MEDIA_VIDEO",
- "WRITE_MEDIA_VIDEO",
- "READ_MEDIA_IMAGES",
- "WRITE_MEDIA_IMAGES",
- "LEGACY_STORAGE",
- "ACCESS_ACCESSIBILITY",
- "READ_DEVICE_IDENTIFIERS",
- "ACCESS_MEDIA_LOCATION",
- "QUERY_ALL_PACKAGES",
- "MANAGE_EXTERNAL_STORAGE",
- "INTERACT_ACROSS_PROFILES",
- "ACTIVATE_PLATFORM_VPN",
- "LOADER_USAGE_STATS",
- "deprecated",
- "AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
- "AUTO_REVOKE_MANAGED_BY_INSTALLER",
- "NO_ISOLATED_STORAGE",
- "PHONE_CALL_MICROPHONE",
- "PHONE_CALL_CAMERA",
- "RECORD_AUDIO_HOTWORD",
- "MANAGE_ONGOING_CALLS",
- "MANAGE_CREDENTIALS",
- "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER",
- "RECORD_AUDIO_OUTPUT",
- "SCHEDULE_EXACT_ALARM",
- "FINE_LOCATION_SOURCE",
- "COARSE_LOCATION_SOURCE",
- "MANAGE_MEDIA",
- "BLUETOOTH_CONNECT",
- "UWB_RANGING",
- "ACTIVITY_RECOGNITION_SOURCE",
- "BLUETOOTH_ADVERTISE",
- "RECORD_INCOMING_PHONE_AUDIO",
- "NEARBY_WIFI_DEVICES",
- "ESTABLISH_VPN_SERVICE",
- "ESTABLISH_VPN_MANAGER",
- "ACCESS_RESTRICTED_SETTINGS",
- "RECEIVE_SOUNDTRIGGER_AUDIO",
- };
-
- /**
- * This optionally maps a permission to an operation. If there
- * is no permission associated with an operation, it is null.
- */
- @UnsupportedAppUsage
- private static String[] sOpPerms = new String[] {
- android.Manifest.permission.ACCESS_COARSE_LOCATION,
- android.Manifest.permission.ACCESS_FINE_LOCATION,
- null,
- android.Manifest.permission.VIBRATE,
- android.Manifest.permission.READ_CONTACTS,
- android.Manifest.permission.WRITE_CONTACTS,
- android.Manifest.permission.READ_CALL_LOG,
- android.Manifest.permission.WRITE_CALL_LOG,
- android.Manifest.permission.READ_CALENDAR,
- android.Manifest.permission.WRITE_CALENDAR,
- android.Manifest.permission.ACCESS_WIFI_STATE,
- android.Manifest.permission.POST_NOTIFICATIONS,
- null, // neighboring cells shares the coarse location perm
- android.Manifest.permission.CALL_PHONE,
- android.Manifest.permission.READ_SMS,
- null, // no permission required for writing sms
- android.Manifest.permission.RECEIVE_SMS,
- android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
- android.Manifest.permission.RECEIVE_MMS,
- android.Manifest.permission.RECEIVE_WAP_PUSH,
- android.Manifest.permission.SEND_SMS,
- android.Manifest.permission.READ_SMS,
- null, // no permission required for writing icc sms
- android.Manifest.permission.WRITE_SETTINGS,
- android.Manifest.permission.SYSTEM_ALERT_WINDOW,
- android.Manifest.permission.ACCESS_NOTIFICATIONS,
- android.Manifest.permission.CAMERA,
- android.Manifest.permission.RECORD_AUDIO,
- null, // no permission for playing audio
- null, // no permission for reading clipboard
- null, // no permission for writing clipboard
- null, // no permission for taking media buttons
- null, // no permission for taking audio focus
- null, // no permission for changing global volume
- null, // no permission for changing voice volume
- null, // no permission for changing ring volume
- null, // no permission for changing media volume
- null, // no permission for changing alarm volume
- null, // no permission for changing notification volume
- null, // no permission for changing bluetooth volume
- android.Manifest.permission.WAKE_LOCK,
- null, // no permission for generic location monitoring
- null, // no permission for high power location monitoring
- android.Manifest.permission.PACKAGE_USAGE_STATS,
- null, // no permission for muting/unmuting microphone
- null, // no permission for displaying toasts
- null, // no permission for projecting media
- null, // no permission for activating vpn
- null, // no permission for supporting wallpaper
- null, // no permission for receiving assist structure
- null, // no permission for receiving assist screenshot
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.USE_FINGERPRINT,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.READ_CELL_BROADCASTS,
- null,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.TURN_SCREEN_ON,
- Manifest.permission.GET_ACCOUNTS,
- null, // no permission for running in background
- null, // no permission for changing accessibility volume
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.REQUEST_INSTALL_PACKAGES,
- null, // no permission for entering picture-in-picture on hide
- Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
- Manifest.permission.ANSWER_PHONE_CALLS,
- null, // no permission for OP_RUN_ANY_IN_BACKGROUND
- Manifest.permission.CHANGE_WIFI_STATE,
- Manifest.permission.REQUEST_DELETE_PACKAGES,
- Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
- Manifest.permission.ACCEPT_HANDOVER,
- Manifest.permission.MANAGE_IPSEC_TUNNELS,
- Manifest.permission.FOREGROUND_SERVICE,
- Manifest.permission.BLUETOOTH_SCAN,
- Manifest.permission.USE_BIOMETRIC,
- Manifest.permission.ACTIVITY_RECOGNITION,
- Manifest.permission.SMS_FINANCIAL_TRANSACTIONS,
- Manifest.permission.READ_MEDIA_AUDIO,
- null, // no permission for OP_WRITE_MEDIA_AUDIO
- Manifest.permission.READ_MEDIA_VIDEO,
- null, // no permission for OP_WRITE_MEDIA_VIDEO
- Manifest.permission.READ_MEDIA_IMAGES,
- null, // no permission for OP_WRITE_MEDIA_IMAGES
- null, // no permission for OP_LEGACY_STORAGE
- null, // no permission for OP_ACCESS_ACCESSIBILITY
- null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
- Manifest.permission.ACCESS_MEDIA_LOCATION,
- null, // no permission for OP_QUERY_ALL_PACKAGES
- Manifest.permission.MANAGE_EXTERNAL_STORAGE,
- android.Manifest.permission.INTERACT_ACROSS_PROFILES,
- null, // no permission for OP_ACTIVATE_PLATFORM_VPN
- android.Manifest.permission.LOADER_USAGE_STATS,
- null, // deprecated operation
- null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
- null, // no permission for OP_NO_ISOLATED_STORAGE
- null, // no permission for OP_PHONE_CALL_MICROPHONE
- null, // no permission for OP_PHONE_CALL_CAMERA
- null, // no permission for OP_RECORD_AUDIO_HOTWORD
- Manifest.permission.MANAGE_ONGOING_CALLS,
- null, // no permission for OP_MANAGE_CREDENTIALS
- Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
- null, // no permission for OP_RECORD_AUDIO_OUTPUT
- Manifest.permission.SCHEDULE_EXACT_ALARM,
- null, // no permission for OP_ACCESS_FINE_LOCATION_SOURCE,
- null, // no permission for OP_ACCESS_COARSE_LOCATION_SOURCE,
- Manifest.permission.MANAGE_MEDIA,
- Manifest.permission.BLUETOOTH_CONNECT,
- Manifest.permission.UWB_RANGING,
- null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE,
- Manifest.permission.BLUETOOTH_ADVERTISE,
- null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO,
- Manifest.permission.NEARBY_WIFI_DEVICES,
- null, // no permission for OP_ESTABLISH_VPN_SERVICE
- null, // no permission for OP_ESTABLISH_VPN_MANAGER
- null, // no permission for OP_ACCESS_RESTRICTED_SETTINGS,
- null, // no permission for OP_RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * Specifies whether an Op should be restricted by a user restriction.
- * Each Op should be filled with a restriction string from UserManager or
- * null to specify it is not affected by any user restriction.
- */
- private static String[] sOpRestrictions = new String[] {
- UserManager.DISALLOW_SHARE_LOCATION, //COARSE_LOCATION
- UserManager.DISALLOW_SHARE_LOCATION, //FINE_LOCATION
- UserManager.DISALLOW_SHARE_LOCATION, //GPS
- null, //VIBRATE
- null, //READ_CONTACTS
- null, //WRITE_CONTACTS
- UserManager.DISALLOW_OUTGOING_CALLS, //READ_CALL_LOG
- UserManager.DISALLOW_OUTGOING_CALLS, //WRITE_CALL_LOG
- null, //READ_CALENDAR
- null, //WRITE_CALENDAR
- UserManager.DISALLOW_SHARE_LOCATION, //WIFI_SCAN
- null, //POST_NOTIFICATION
- null, //NEIGHBORING_CELLS
- null, //CALL_PHONE
- UserManager.DISALLOW_SMS, //READ_SMS
- UserManager.DISALLOW_SMS, //WRITE_SMS
- UserManager.DISALLOW_SMS, //RECEIVE_SMS
- null, //RECEIVE_EMERGENCY_SMS
- UserManager.DISALLOW_SMS, //RECEIVE_MMS
- null, //RECEIVE_WAP_PUSH
- UserManager.DISALLOW_SMS, //SEND_SMS
- UserManager.DISALLOW_SMS, //READ_ICC_SMS
- UserManager.DISALLOW_SMS, //WRITE_ICC_SMS
- null, //WRITE_SETTINGS
- UserManager.DISALLOW_CREATE_WINDOWS, //SYSTEM_ALERT_WINDOW
- null, //ACCESS_NOTIFICATIONS
- UserManager.DISALLOW_CAMERA, //CAMERA
- UserManager.DISALLOW_RECORD_AUDIO, //RECORD_AUDIO
- null, //PLAY_AUDIO
- null, //READ_CLIPBOARD
- null, //WRITE_CLIPBOARD
- null, //TAKE_MEDIA_BUTTONS
- null, //TAKE_AUDIO_FOCUS
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_MASTER_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_VOICE_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_RING_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_MEDIA_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ALARM_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_NOTIFICATION_VOLUME
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_BLUETOOTH_VOLUME
- null, //WAKE_LOCK
- UserManager.DISALLOW_SHARE_LOCATION, //MONITOR_LOCATION
- UserManager.DISALLOW_SHARE_LOCATION, //MONITOR_HIGH_POWER_LOCATION
- null, //GET_USAGE_STATS
- UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE
- UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
- null, //PROJECT_MEDIA
- null, // ACTIVATE_VPN
- UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
- null, // ASSIST_STRUCTURE
- null, // ASSIST_SCREENSHOT
- null, // READ_PHONE_STATE
- null, // ADD_VOICEMAIL
- null, // USE_SIP
- null, // PROCESS_OUTGOING_CALLS
- null, // USE_FINGERPRINT
- null, // BODY_SENSORS
- null, // READ_CELL_BROADCASTS
- null, // MOCK_LOCATION
- null, // READ_EXTERNAL_STORAGE
- null, // WRITE_EXTERNAL_STORAGE
- null, // TURN_SCREEN_ON
- null, // GET_ACCOUNTS
- null, // RUN_IN_BACKGROUND
- UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
- null, // READ_PHONE_NUMBERS
- null, // REQUEST_INSTALL_PACKAGES
- null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
- null, // INSTANT_APP_START_FOREGROUND
- null, // ANSWER_PHONE_CALLS
- null, // OP_RUN_ANY_IN_BACKGROUND
- null, // OP_CHANGE_WIFI_STATE
- null, // REQUEST_DELETE_PACKAGES
- null, // OP_BIND_ACCESSIBILITY_SERVICE
- null, // ACCEPT_HANDOVER
- null, // MANAGE_IPSEC_TUNNELS
- null, // START_FOREGROUND
- null, // maybe should be UserManager.DISALLOW_SHARE_LOCATION, //BLUETOOTH_SCAN
- null, // USE_BIOMETRIC
- null, // ACTIVITY_RECOGNITION
- UserManager.DISALLOW_SMS, // SMS_FINANCIAL_TRANSACTIONS
- null, // READ_MEDIA_AUDIO
- null, // WRITE_MEDIA_AUDIO
- null, // READ_MEDIA_VIDEO
- null, // WRITE_MEDIA_VIDEO
- null, // READ_MEDIA_IMAGES
- null, // WRITE_MEDIA_IMAGES
- null, // LEGACY_STORAGE
- null, // ACCESS_ACCESSIBILITY
- null, // READ_DEVICE_IDENTIFIERS
- null, // ACCESS_MEDIA_LOCATION
- null, // QUERY_ALL_PACKAGES
- null, // MANAGE_EXTERNAL_STORAGE
- null, // INTERACT_ACROSS_PROFILES
- null, // ACTIVATE_PLATFORM_VPN
- null, // LOADER_USAGE_STATS
- null, // deprecated operation
- null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
- null, // NO_ISOLATED_STORAGE
- null, // PHONE_CALL_MICROPHONE
- null, // PHONE_CALL_MICROPHONE
- null, // RECORD_AUDIO_HOTWORD
- null, // MANAGE_ONGOING_CALLS
- null, // MANAGE_CREDENTIALS
- null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- null, // RECORD_AUDIO_OUTPUT
- null, // SCHEDULE_EXACT_ALARM
- null, // ACCESS_FINE_LOCATION_SOURCE
- null, // ACCESS_COARSE_LOCATION_SOURCE
- null, // MANAGE_MEDIA
- null, // BLUETOOTH_CONNECT
- null, // UWB_RANGING
- null, // ACTIVITY_RECOGNITION_SOURCE
- null, // BLUETOOTH_ADVERTISE
- null, // RECORD_INCOMING_PHONE_AUDIO
- null, // NEARBY_WIFI_DEVICES
- null, // ESTABLISH_VPN_SERVICE
- null, // ESTABLISH_VPN_MANAGER
- null, // ACCESS_RESTRICTED_SETTINGS
- null, // RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * In which cases should an app be allowed to bypass the {@link #setUserRestriction user
- * restriction} for a certain app-op.
- */
- private static RestrictionBypass[] sOpAllowSystemRestrictionBypass = new RestrictionBypass[] {
- new RestrictionBypass(true, false, false), //COARSE_LOCATION
- new RestrictionBypass(true, false, false), //FINE_LOCATION
- null, //GPS
- null, //VIBRATE
- null, //READ_CONTACTS
- null, //WRITE_CONTACTS
- null, //READ_CALL_LOG
- null, //WRITE_CALL_LOG
- null, //READ_CALENDAR
- null, //WRITE_CALENDAR
- new RestrictionBypass(false, true, false), //WIFI_SCAN
- null, //POST_NOTIFICATION
- null, //NEIGHBORING_CELLS
- null, //CALL_PHONE
- null, //READ_SMS
- null, //WRITE_SMS
- null, //RECEIVE_SMS
- null, //RECEIVE_EMERGECY_SMS
- null, //RECEIVE_MMS
- null, //RECEIVE_WAP_PUSH
- null, //SEND_SMS
- null, //READ_ICC_SMS
- null, //WRITE_ICC_SMS
- null, //WRITE_SETTINGS
- new RestrictionBypass(false, true, false), //SYSTEM_ALERT_WINDOW
- null, //ACCESS_NOTIFICATIONS
- null, //CAMERA
- new RestrictionBypass(false, false, true), //RECORD_AUDIO
- null, //PLAY_AUDIO
- null, //READ_CLIPBOARD
- null, //WRITE_CLIPBOARD
- null, //TAKE_MEDIA_BUTTONS
- null, //TAKE_AUDIO_FOCUS
- null, //AUDIO_MASTER_VOLUME
- null, //AUDIO_VOICE_VOLUME
- null, //AUDIO_RING_VOLUME
- null, //AUDIO_MEDIA_VOLUME
- null, //AUDIO_ALARM_VOLUME
- null, //AUDIO_NOTIFICATION_VOLUME
- null, //AUDIO_BLUETOOTH_VOLUME
- null, //WAKE_LOCK
- null, //MONITOR_LOCATION
- null, //MONITOR_HIGH_POWER_LOCATION
- null, //GET_USAGE_STATS
- null, //MUTE_MICROPHONE
- new RestrictionBypass(false, true, false), //TOAST_WINDOW
- null, //PROJECT_MEDIA
- null, //ACTIVATE_VPN
- null, //WALLPAPER
- null, //ASSIST_STRUCTURE
- null, //ASSIST_SCREENSHOT
- null, //READ_PHONE_STATE
- null, //ADD_VOICEMAIL
- null, // USE_SIP
- null, // PROCESS_OUTGOING_CALLS
- null, // USE_FINGERPRINT
- null, // BODY_SENSORS
- null, // READ_CELL_BROADCASTS
- null, // MOCK_LOCATION
- null, // READ_EXTERNAL_STORAGE
- null, // WRITE_EXTERNAL_STORAGE
- null, // TURN_SCREEN_ON
- null, // GET_ACCOUNTS
- null, // RUN_IN_BACKGROUND
- null, // AUDIO_ACCESSIBILITY_VOLUME
- null, // READ_PHONE_NUMBERS
- null, // REQUEST_INSTALL_PACKAGES
- null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
- null, // INSTANT_APP_START_FOREGROUND
- null, // ANSWER_PHONE_CALLS
- null, // OP_RUN_ANY_IN_BACKGROUND
- null, // OP_CHANGE_WIFI_STATE
- null, // OP_REQUEST_DELETE_PACKAGES
- null, // OP_BIND_ACCESSIBILITY_SERVICE
- null, // ACCEPT_HANDOVER
- null, // MANAGE_IPSEC_HANDOVERS
- null, // START_FOREGROUND
- new RestrictionBypass(false, true, false), // BLUETOOTH_SCAN
- null, // USE_BIOMETRIC
- null, // ACTIVITY_RECOGNITION
- null, // SMS_FINANCIAL_TRANSACTIONS
- null, // READ_MEDIA_AUDIO
- null, // WRITE_MEDIA_AUDIO
- null, // READ_MEDIA_VIDEO
- null, // WRITE_MEDIA_VIDEO
- null, // READ_MEDIA_IMAGES
- null, // WRITE_MEDIA_IMAGES
- null, // LEGACY_STORAGE
- null, // ACCESS_ACCESSIBILITY
- null, // READ_DEVICE_IDENTIFIERS
- null, // ACCESS_MEDIA_LOCATION
- null, // QUERY_ALL_PACKAGES
- null, // MANAGE_EXTERNAL_STORAGE
- null, // INTERACT_ACROSS_PROFILES
- null, // ACTIVATE_PLATFORM_VPN
- null, // LOADER_USAGE_STATS
- null, // deprecated operation
- null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
- null, // NO_ISOLATED_STORAGE
- null, // PHONE_CALL_MICROPHONE
- null, // PHONE_CALL_CAMERA
- null, // RECORD_AUDIO_HOTWORD
- null, // MANAGE_ONGOING_CALLS
- null, // MANAGE_CREDENTIALS
- null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- null, // RECORD_AUDIO_OUTPUT
- null, // SCHEDULE_EXACT_ALARM
- null, // ACCESS_FINE_LOCATION_SOURCE
- null, // ACCESS_COARSE_LOCATION_SOURCE
- null, // MANAGE_MEDIA
- null, // BLUETOOTH_CONNECT
- null, // UWB_RANGING
- null, // ACTIVITY_RECOGNITION_SOURCE
- null, // BLUETOOTH_ADVERTISE
- null, // RECORD_INCOMING_PHONE_AUDIO
- null, // NEARBY_WIFI_DEVICES
- null, // ESTABLISH_VPN_SERVICE
- null, // ESTABLISH_VPN_MANAGER
- null, // ACCESS_RESTRICTED_SETTINGS
- null, // RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * This specifies the default mode for each operation.
- */
- private static int[] sOpDefaultMode = new int[] {
- AppOpsManager.MODE_ALLOWED, // COARSE_LOCATION
- AppOpsManager.MODE_ALLOWED, // FINE_LOCATION
- AppOpsManager.MODE_ALLOWED, // GPS
- AppOpsManager.MODE_ALLOWED, // VIBRATE
- AppOpsManager.MODE_ALLOWED, // READ_CONTACTS
- AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS
- AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG
- AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG
- AppOpsManager.MODE_ALLOWED, // READ_CALENDAR
- AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR
- AppOpsManager.MODE_ALLOWED, // WIFI_SCAN
- AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION
- AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS
- AppOpsManager.MODE_ALLOWED, // CALL_PHONE
- AppOpsManager.MODE_ALLOWED, // READ_SMS
- AppOpsManager.MODE_IGNORED, // WRITE_SMS
- AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS
- AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST
- AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS
- AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH
- AppOpsManager.MODE_ALLOWED, // SEND_SMS
- AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS
- AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS
- AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS
- getSystemAlertWindowDefault(), // SYSTEM_ALERT_WINDOW
- AppOpsManager.MODE_ALLOWED, // ACCESS_NOTIFICATIONS
- AppOpsManager.MODE_ALLOWED, // CAMERA
- AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO
- AppOpsManager.MODE_ALLOWED, // PLAY_AUDIO
- AppOpsManager.MODE_ALLOWED, // READ_CLIPBOARD
- AppOpsManager.MODE_ALLOWED, // WRITE_CLIPBOARD
- AppOpsManager.MODE_ALLOWED, // TAKE_MEDIA_BUTTONS
- AppOpsManager.MODE_ALLOWED, // TAKE_AUDIO_FOCUS
- AppOpsManager.MODE_ALLOWED, // AUDIO_MASTER_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_VOICE_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_RING_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_MEDIA_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_ALARM_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_NOTIFICATION_VOLUME
- AppOpsManager.MODE_ALLOWED, // AUDIO_BLUETOOTH_VOLUME
- AppOpsManager.MODE_ALLOWED, // WAKE_LOCK
- AppOpsManager.MODE_ALLOWED, // MONITOR_LOCATION
- AppOpsManager.MODE_ALLOWED, // MONITOR_HIGH_POWER_LOCATION
- AppOpsManager.MODE_DEFAULT, // GET_USAGE_STATS
- AppOpsManager.MODE_ALLOWED, // MUTE_MICROPHONE
- AppOpsManager.MODE_ALLOWED, // TOAST_WINDOW
- AppOpsManager.MODE_IGNORED, // PROJECT_MEDIA
- AppOpsManager.MODE_IGNORED, // ACTIVATE_VPN
- AppOpsManager.MODE_ALLOWED, // WRITE_WALLPAPER
- AppOpsManager.MODE_ALLOWED, // ASSIST_STRUCTURE
- AppOpsManager.MODE_ALLOWED, // ASSIST_SCREENSHOT
- AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE
- AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL
- AppOpsManager.MODE_ALLOWED, // USE_SIP
- AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS
- AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT
- AppOpsManager.MODE_ALLOWED, // BODY_SENSORS
- AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS
- AppOpsManager.MODE_ERRORED, // MOCK_LOCATION
- AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE
- AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE
- AppOpsManager.MODE_ERRORED, // TURN_SCREEN_ON
- AppOpsManager.MODE_ALLOWED, // GET_ACCOUNTS
- AppOpsManager.MODE_ALLOWED, // RUN_IN_BACKGROUND
- AppOpsManager.MODE_ALLOWED, // AUDIO_ACCESSIBILITY_VOLUME
- AppOpsManager.MODE_ALLOWED, // READ_PHONE_NUMBERS
- AppOpsManager.MODE_DEFAULT, // REQUEST_INSTALL_PACKAGES
- AppOpsManager.MODE_ALLOWED, // PICTURE_IN_PICTURE
- AppOpsManager.MODE_DEFAULT, // INSTANT_APP_START_FOREGROUND
- AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
- AppOpsManager.MODE_ALLOWED, // RUN_ANY_IN_BACKGROUND
- AppOpsManager.MODE_ALLOWED, // CHANGE_WIFI_STATE
- AppOpsManager.MODE_ALLOWED, // REQUEST_DELETE_PACKAGES
- AppOpsManager.MODE_ALLOWED, // BIND_ACCESSIBILITY_SERVICE
- AppOpsManager.MODE_ALLOWED, // ACCEPT_HANDOVER
- AppOpsManager.MODE_ERRORED, // MANAGE_IPSEC_TUNNELS
- AppOpsManager.MODE_ALLOWED, // START_FOREGROUND
- AppOpsManager.MODE_ALLOWED, // BLUETOOTH_SCAN
- AppOpsManager.MODE_ALLOWED, // USE_BIOMETRIC
- AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION
- AppOpsManager.MODE_DEFAULT, // SMS_FINANCIAL_TRANSACTIONS
- AppOpsManager.MODE_ALLOWED, // READ_MEDIA_AUDIO
- AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_AUDIO
- AppOpsManager.MODE_ALLOWED, // READ_MEDIA_VIDEO
- AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_VIDEO
- AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES
- AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES
- AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
- AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
- AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
- AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION
- AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
- AppOpsManager.MODE_DEFAULT, // MANAGE_EXTERNAL_STORAGE
- AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
- AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
- AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
- AppOpsManager.MODE_IGNORED, // deprecated operation
- AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
- AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
- AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
- AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
- AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_HOTWORD
- AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
- AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
- AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_OUTPUT
- AppOpsManager.MODE_DEFAULT, // SCHEDULE_EXACT_ALARM
- AppOpsManager.MODE_ALLOWED, // ACCESS_FINE_LOCATION_SOURCE
- AppOpsManager.MODE_ALLOWED, // ACCESS_COARSE_LOCATION_SOURCE
- AppOpsManager.MODE_DEFAULT, // MANAGE_MEDIA
- AppOpsManager.MODE_ALLOWED, // BLUETOOTH_CONNECT
- AppOpsManager.MODE_ALLOWED, // UWB_RANGING
- AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE
- AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE
- AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO
- AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES
- AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE
- AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER
- AppOpsManager.MODE_ALLOWED, // ACCESS_RESTRICTED_SETTINGS,
- AppOpsManager.MODE_ALLOWED, // RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * This specifies whether each option is allowed to be reset
- * when resetting all app preferences. Disable reset for
- * app ops that are under strong control of some part of the
- * system (such as OP_WRITE_SMS, which should be allowed only
- * for whichever app is selected as the current SMS app).
- */
- private static boolean[] sOpDisableReset = new boolean[] {
- false, // COARSE_LOCATION
- false, // FINE_LOCATION
- false, // GPS
- false, // VIBRATE
- false, // READ_CONTACTS
- false, // WRITE_CONTACTS
- false, // READ_CALL_LOG
- false, // WRITE_CALL_LOG
- false, // READ_CALENDAR
- false, // WRITE_CALENDAR
- false, // WIFI_SCAN
- false, // POST_NOTIFICATION
- false, // NEIGHBORING_CELLS
- false, // CALL_PHONE
- true, // READ_SMS
- true, // WRITE_SMS
- true, // RECEIVE_SMS
- false, // RECEIVE_EMERGENCY_BROADCAST
- false, // RECEIVE_MMS
- true, // RECEIVE_WAP_PUSH
- true, // SEND_SMS
- false, // READ_ICC_SMS
- false, // WRITE_ICC_SMS
- false, // WRITE_SETTINGS
- false, // SYSTEM_ALERT_WINDOW
- false, // ACCESS_NOTIFICATIONS
- false, // CAMERA
- false, // RECORD_AUDIO
- false, // PLAY_AUDIO
- false, // READ_CLIPBOARD
- false, // WRITE_CLIPBOARD
- false, // TAKE_MEDIA_BUTTONS
- false, // TAKE_AUDIO_FOCUS
- false, // AUDIO_MASTER_VOLUME
- false, // AUDIO_VOICE_VOLUME
- false, // AUDIO_RING_VOLUME
- false, // AUDIO_MEDIA_VOLUME
- false, // AUDIO_ALARM_VOLUME
- false, // AUDIO_NOTIFICATION_VOLUME
- false, // AUDIO_BLUETOOTH_VOLUME
- false, // WAKE_LOCK
- false, // MONITOR_LOCATION
- false, // MONITOR_HIGH_POWER_LOCATION
- false, // GET_USAGE_STATS
- false, // MUTE_MICROPHONE
- false, // TOAST_WINDOW
- false, // PROJECT_MEDIA
- false, // ACTIVATE_VPN
- false, // WRITE_WALLPAPER
- false, // ASSIST_STRUCTURE
- false, // ASSIST_SCREENSHOT
- false, // READ_PHONE_STATE
- false, // ADD_VOICEMAIL
- false, // USE_SIP
- false, // PROCESS_OUTGOING_CALLS
- false, // USE_FINGERPRINT
- false, // BODY_SENSORS
- true, // READ_CELL_BROADCASTS
- false, // MOCK_LOCATION
- false, // READ_EXTERNAL_STORAGE
- false, // WRITE_EXTERNAL_STORAGE
- false, // TURN_SCREEN_ON
- false, // GET_ACCOUNTS
- false, // RUN_IN_BACKGROUND
- false, // AUDIO_ACCESSIBILITY_VOLUME
- false, // READ_PHONE_NUMBERS
- false, // REQUEST_INSTALL_PACKAGES
- false, // PICTURE_IN_PICTURE
- false, // INSTANT_APP_START_FOREGROUND
- false, // ANSWER_PHONE_CALLS
- false, // RUN_ANY_IN_BACKGROUND
- false, // CHANGE_WIFI_STATE
- false, // REQUEST_DELETE_PACKAGES
- false, // BIND_ACCESSIBILITY_SERVICE
- false, // ACCEPT_HANDOVER
- false, // MANAGE_IPSEC_TUNNELS
- false, // START_FOREGROUND
- false, // BLUETOOTH_SCAN
- false, // USE_BIOMETRIC
- false, // ACTIVITY_RECOGNITION
- false, // SMS_FINANCIAL_TRANSACTIONS
- false, // READ_MEDIA_AUDIO
- false, // WRITE_MEDIA_AUDIO
- false, // READ_MEDIA_VIDEO
- true, // WRITE_MEDIA_VIDEO
- false, // READ_MEDIA_IMAGES
- true, // WRITE_MEDIA_IMAGES
- true, // LEGACY_STORAGE
- false, // ACCESS_ACCESSIBILITY
- false, // READ_DEVICE_IDENTIFIERS
- false, // ACCESS_MEDIA_LOCATION
- false, // QUERY_ALL_PACKAGES
- false, // MANAGE_EXTERNAL_STORAGE
- false, // INTERACT_ACROSS_PROFILES
- false, // ACTIVATE_PLATFORM_VPN
- false, // LOADER_USAGE_STATS
- false, // deprecated operation
- false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
- true, // NO_ISOLATED_STORAGE
- false, // PHONE_CALL_MICROPHONE
- false, // PHONE_CALL_CAMERA
- false, // RECORD_AUDIO_HOTWORD
- true, // MANAGE_ONGOING_CALLS
- false, // MANAGE_CREDENTIALS
- true, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- false, // RECORD_AUDIO_OUTPUT
- false, // SCHEDULE_EXACT_ALARM
- false, // ACCESS_FINE_LOCATION_SOURCE
- false, // ACCESS_COARSE_LOCATION_SOURCE
- false, // MANAGE_MEDIA
- false, // BLUETOOTH_CONNECT
- false, // UWB_RANGING
- false, // ACTIVITY_RECOGNITION_SOURCE
- false, // BLUETOOTH_ADVERTISE
- false, // RECORD_INCOMING_PHONE_AUDIO
- false, // NEARBY_WIFI_DEVICES
- false, // OP_ESTABLISH_VPN_SERVICE
- false, // OP_ESTABLISH_VPN_MANAGER
- true, // ACCESS_RESTRICTED_SETTINGS
- false, // RECEIVE_SOUNDTRIGGER_AUDIO
- };
-
- /**
- * This specifies whether each option is only allowed to be read
- * by apps with manage appops permission.
- */
- private static boolean[] sOpRestrictRead = new boolean[] {
- false, // COARSE_LOCATION
- false, // FINE_LOCATION
- false, // GPS
- false, // VIBRATE
- false, // READ_CONTACTS
- false, // WRITE_CONTACTS
- false, // READ_CALL_LOG
- false, // WRITE_CALL_LOG
- false, // READ_CALENDAR
- false, // WRITE_CALENDAR
- false, // WIFI_SCAN
- false, // POST_NOTIFICATION
- false, // NEIGHBORING_CELLS
- false, // CALL_PHONE
- false, // READ_SMS
- false, // WRITE_SMS
- false, // RECEIVE_SMS
- false, // RECEIVE_EMERGENCY_BROADCAST
- false, // RECEIVE_MMS
- false, // RECEIVE_WAP_PUSH
- false, // SEND_SMS
- false, // READ_ICC_SMS
- false, // WRITE_ICC_SMS
- false, // WRITE_SETTINGS
- false, // SYSTEM_ALERT_WINDOW
- false, // ACCESS_NOTIFICATIONS
- false, // CAMERA
- false, // RECORD_AUDIO
- false, // PLAY_AUDIO
- false, // READ_CLIPBOARD
- false, // WRITE_CLIPBOARD
- false, // TAKE_MEDIA_BUTTONS
- false, // TAKE_AUDIO_FOCUS
- false, // AUDIO_MASTER_VOLUME
- false, // AUDIO_VOICE_VOLUME
- false, // AUDIO_RING_VOLUME
- false, // AUDIO_MEDIA_VOLUME
- false, // AUDIO_ALARM_VOLUME
- false, // AUDIO_NOTIFICATION_VOLUME
- false, // AUDIO_BLUETOOTH_VOLUME
- false, // WAKE_LOCK
- false, // MONITOR_LOCATION
- false, // MONITOR_HIGH_POWER_LOCATION
- false, // GET_USAGE_STATS
- false, // MUTE_MICROPHONE
- false, // TOAST_WINDOW
- false, // PROJECT_MEDIA
- false, // ACTIVATE_VPN
- false, // WRITE_WALLPAPER
- false, // ASSIST_STRUCTURE
- false, // ASSIST_SCREENSHOT
- false, // READ_PHONE_STATE
- false, // ADD_VOICEMAIL
- false, // USE_SIP
- false, // PROCESS_OUTGOING_CALLS
- false, // USE_FINGERPRINT
- false, // BODY_SENSORS
- false, // READ_CELL_BROADCASTS
- false, // MOCK_LOCATION
- false, // READ_EXTERNAL_STORAGE
- false, // WRITE_EXTERNAL_STORAGE
- false, // TURN_SCREEN_ON
- false, // GET_ACCOUNTS
- false, // RUN_IN_BACKGROUND
- false, // AUDIO_ACCESSIBILITY_VOLUME
- false, // READ_PHONE_NUMBERS
- false, // REQUEST_INSTALL_PACKAGES
- false, // PICTURE_IN_PICTURE
- false, // INSTANT_APP_START_FOREGROUND
- false, // ANSWER_PHONE_CALLS
- false, // RUN_ANY_IN_BACKGROUND
- false, // CHANGE_WIFI_STATE
- false, // REQUEST_DELETE_PACKAGES
- false, // BIND_ACCESSIBILITY_SERVICE
- false, // ACCEPT_HANDOVER
- false, // MANAGE_IPSEC_TUNNELS
- false, // START_FOREGROUND
- false, // BLUETOOTH_SCAN
- false, // USE_BIOMETRIC
- false, // ACTIVITY_RECOGNITION
- false, // SMS_FINANCIAL_TRANSACTIONS
- false, // READ_MEDIA_AUDIO
- false, // WRITE_MEDIA_AUDIO
- false, // READ_MEDIA_VIDEO
- false, // WRITE_MEDIA_VIDEO
- false, // READ_MEDIA_IMAGES
- false, // WRITE_MEDIA_IMAGES
- false, // LEGACY_STORAGE
- false, // ACCESS_ACCESSIBILITY
- false, // READ_DEVICE_IDENTIFIERS
- false, // ACCESS_MEDIA_LOCATION
- false, // QUERY_ALL_PACKAGES
- false, // MANAGE_EXTERNAL_STORAGE
- false, // INTERACT_ACROSS_PROFILES
- false, // ACTIVATE_PLATFORM_VPN
- false, // LOADER_USAGE_STATS
- false, // deprecated operation
- false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
- false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
- false, // NO_ISOLATED_STORAGE
- false, // PHONE_CALL_MICROPHONE
- false, // PHONE_CALL_CAMERA
- false, // RECORD_AUDIO_HOTWORD
- false, // MANAGE_ONGOING_CALLS
- false, // MANAGE_CREDENTIALS
- false, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
- false, // RECORD_AUDIO_OUTPUT
- false, // SCHEDULE_EXACT_ALARM
- false, // ACCESS_FINE_LOCATION_SOURCE
- false, // ACCESS_COARSE_LOCATION_SOURCE
- false, // MANAGE_MEDIA
- false, // BLUETOOTH_CONNECT
- false, // UWB_RANGING
- false, // ACTIVITY_RECOGNITION_SOURCE
- false, // BLUETOOTH_ADVERTISE
- false, // RECORD_INCOMING_PHONE_AUDIO
- false, // NEARBY_WIFI_DEVICES
- false, // OP_ESTABLISH_VPN_SERVICE
- false, // OP_ESTABLISH_VPN_MANAGER
- true, // ACCESS_RESTRICTED_SETTINGS
- false, // RECEIVE_SOUNDTRIGGER_AUDIO
+ static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{
+ new AppOpInfo.Builder(OP_COARSE_LOCATION, OPSTR_COARSE_LOCATION, "COARSE_LOCATION")
+ .setPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(true, false, false))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_FINE_LOCATION, OPSTR_FINE_LOCATION, "FINE_LOCATION")
+ .setPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(true, false, false))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_GPS, OPSTR_GPS, "GPS")
+ .setSwitchCode(OP_COARSE_LOCATION)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_VIBRATE, OPSTR_VIBRATE, "VIBRATE")
+ .setSwitchCode(OP_VIBRATE).setPermission(android.Manifest.permission.VIBRATE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_CONTACTS, OPSTR_READ_CONTACTS, "READ_CONTACTS")
+ .setPermission(android.Manifest.permission.READ_CONTACTS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_CONTACTS, OPSTR_WRITE_CONTACTS, "WRITE_CONTACTS")
+ .setPermission(android.Manifest.permission.WRITE_CONTACTS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_CALL_LOG, OPSTR_READ_CALL_LOG, "READ_CALL_LOG")
+ .setPermission(android.Manifest.permission.READ_CALL_LOG)
+ .setRestriction(UserManager.DISALLOW_OUTGOING_CALLS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_CALL_LOG, OPSTR_WRITE_CALL_LOG, "WRITE_CALL_LOG")
+ .setPermission(android.Manifest.permission.WRITE_CALL_LOG)
+ .setRestriction(UserManager.DISALLOW_OUTGOING_CALLS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_CALENDAR, OPSTR_READ_CALENDAR, "READ_CALENDAR")
+ .setPermission(android.Manifest.permission.READ_CALENDAR)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_CALENDAR, OPSTR_WRITE_CALENDAR, "WRITE_CALENDAR")
+ .setPermission(android.Manifest.permission.WRITE_CALENDAR)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WIFI_SCAN, OPSTR_WIFI_SCAN, "WIFI_SCAN")
+ .setSwitchCode(OP_COARSE_LOCATION)
+ .setPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(false, true, false))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_POST_NOTIFICATION, OPSTR_POST_NOTIFICATION, "POST_NOTIFICATION")
+ .setPermission(android.Manifest.permission.POST_NOTIFICATIONS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_NEIGHBORING_CELLS, OPSTR_NEIGHBORING_CELLS, "NEIGHBORING_CELLS")
+ .setSwitchCode(OP_COARSE_LOCATION).setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_CALL_PHONE, OPSTR_CALL_PHONE, "CALL_PHONE")
+ .setSwitchCode(OP_CALL_PHONE).setPermission(android.Manifest.permission.CALL_PHONE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_SMS, OPSTR_READ_SMS, "READ_SMS")
+ .setPermission(android.Manifest.permission.READ_SMS)
+ .setRestriction(UserManager.DISALLOW_SMS).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_WRITE_SMS, OPSTR_WRITE_SMS, "WRITE_SMS")
+ .setRestriction(UserManager.DISALLOW_SMS)
+ .setDefaultMode(AppOpsManager.MODE_IGNORED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_RECEIVE_SMS, OPSTR_RECEIVE_SMS, "RECEIVE_SMS")
+ .setPermission(android.Manifest.permission.RECEIVE_SMS)
+ .setRestriction(UserManager.DISALLOW_SMS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_RECEIVE_EMERGECY_SMS, OPSTR_RECEIVE_EMERGENCY_BROADCAST,
+ "RECEIVE_EMERGENCY_BROADCAST").setSwitchCode(OP_RECEIVE_SMS)
+ .setPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECEIVE_MMS, OPSTR_RECEIVE_MMS, "RECEIVE_MMS")
+ .setPermission(android.Manifest.permission.RECEIVE_MMS)
+ .setRestriction(UserManager.DISALLOW_SMS).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_RECEIVE_WAP_PUSH, OPSTR_RECEIVE_WAP_PUSH, "RECEIVE_WAP_PUSH")
+ .setPermission(android.Manifest.permission.RECEIVE_WAP_PUSH)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_SEND_SMS, OPSTR_SEND_SMS, "SEND_SMS")
+ .setPermission(android.Manifest.permission.SEND_SMS)
+ .setRestriction(UserManager.DISALLOW_SMS).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_READ_ICC_SMS, OPSTR_READ_ICC_SMS, "READ_ICC_SMS")
+ .setSwitchCode(OP_READ_SMS).setPermission(android.Manifest.permission.READ_SMS)
+ .setRestriction(UserManager.DISALLOW_SMS).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_WRITE_ICC_SMS, OPSTR_WRITE_ICC_SMS, "WRITE_ICC_SMS")
+ .setSwitchCode(OP_WRITE_SMS).setRestriction(UserManager.DISALLOW_SMS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_SETTINGS, OPSTR_WRITE_SETTINGS, "WRITE_SETTINGS")
+ .setPermission(android.Manifest.permission.WRITE_SETTINGS).build(),
+ new AppOpInfo.Builder(OP_SYSTEM_ALERT_WINDOW, OPSTR_SYSTEM_ALERT_WINDOW,
+ "SYSTEM_ALERT_WINDOW")
+ .setPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW)
+ .setRestriction(UserManager.DISALLOW_CREATE_WINDOWS)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(false, true, false))
+ .setDefaultMode(getSystemAlertWindowDefault()).build(),
+ new AppOpInfo.Builder(OP_ACCESS_NOTIFICATIONS, OPSTR_ACCESS_NOTIFICATIONS,
+ "ACCESS_NOTIFICATIONS")
+ .setPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_CAMERA, OPSTR_CAMERA, "CAMERA")
+ .setPermission(android.Manifest.permission.CAMERA)
+ .setRestriction(UserManager.DISALLOW_CAMERA)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECORD_AUDIO, OPSTR_RECORD_AUDIO, "RECORD_AUDIO")
+ .setPermission(android.Manifest.permission.RECORD_AUDIO)
+ .setRestriction(UserManager.DISALLOW_RECORD_AUDIO)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(false, false, true))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_PLAY_AUDIO, OPSTR_PLAY_AUDIO, "PLAY_AUDIO")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_CLIPBOARD, OPSTR_READ_CLIPBOARD, "READ_CLIPBOARD")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_CLIPBOARD, OPSTR_WRITE_CLIPBOARD, "WRITE_CLIPBOARD")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_TAKE_MEDIA_BUTTONS, OPSTR_TAKE_MEDIA_BUTTONS, "TAKE_MEDIA_BUTTONS")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_TAKE_AUDIO_FOCUS, OPSTR_TAKE_AUDIO_FOCUS, "TAKE_AUDIO_FOCUS")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_MASTER_VOLUME, OPSTR_AUDIO_MASTER_VOLUME,
+ "AUDIO_MASTER_VOLUME").setSwitchCode(OP_AUDIO_MASTER_VOLUME)
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_VOICE_VOLUME, OPSTR_AUDIO_VOICE_VOLUME, "AUDIO_VOICE_VOLUME")
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_RING_VOLUME, OPSTR_AUDIO_RING_VOLUME, "AUDIO_RING_VOLUME")
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_MEDIA_VOLUME, OPSTR_AUDIO_MEDIA_VOLUME, "AUDIO_MEDIA_VOLUME")
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_ALARM_VOLUME, OPSTR_AUDIO_ALARM_VOLUME, "AUDIO_ALARM_VOLUME")
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_NOTIFICATION_VOLUME, OPSTR_AUDIO_NOTIFICATION_VOLUME,
+ "AUDIO_NOTIFICATION_VOLUME").setSwitchCode(OP_AUDIO_NOTIFICATION_VOLUME)
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_AUDIO_BLUETOOTH_VOLUME, OPSTR_AUDIO_BLUETOOTH_VOLUME,
+ "AUDIO_BLUETOOTH_VOLUME").setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WAKE_LOCK, OPSTR_WAKE_LOCK, "WAKE_LOCK")
+ .setPermission(android.Manifest.permission.WAKE_LOCK)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_MONITOR_LOCATION, OPSTR_MONITOR_LOCATION, "MONITOR_LOCATION")
+ .setSwitchCode(OP_COARSE_LOCATION)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_MONITOR_HIGH_POWER_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION,
+ "MONITOR_HIGH_POWER_LOCATION").setSwitchCode(OP_COARSE_LOCATION)
+ .setRestriction(UserManager.DISALLOW_SHARE_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_GET_USAGE_STATS, OPSTR_GET_USAGE_STATS, "GET_USAGE_STATS")
+ .setPermission(android.Manifest.permission.PACKAGE_USAGE_STATS).build(),
+ new AppOpInfo.Builder(OP_MUTE_MICROPHONE, OPSTR_MUTE_MICROPHONE, "MUTE_MICROPHONE")
+ .setRestriction(UserManager.DISALLOW_UNMUTE_MICROPHONE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_TOAST_WINDOW, OPSTR_TOAST_WINDOW, "TOAST_WINDOW")
+ .setRestriction(UserManager.DISALLOW_CREATE_WINDOWS)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(false, true, false))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_PROJECT_MEDIA, OPSTR_PROJECT_MEDIA, "PROJECT_MEDIA")
+ .setDefaultMode(AppOpsManager.MODE_IGNORED).build(),
+ new AppOpInfo.Builder(OP_ACTIVATE_VPN, OPSTR_ACTIVATE_VPN, "ACTIVATE_VPN")
+ .setDefaultMode(AppOpsManager.MODE_IGNORED).build(),
+ new AppOpInfo.Builder(OP_WRITE_WALLPAPER, OPSTR_WRITE_WALLPAPER, "WRITE_WALLPAPER")
+ .setRestriction(UserManager.DISALLOW_WALLPAPER)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ASSIST_STRUCTURE, OPSTR_ASSIST_STRUCTURE, "ASSIST_STRUCTURE")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ASSIST_SCREENSHOT, OPSTR_ASSIST_SCREENSHOT, "ASSIST_SCREENSHOT")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_READ_PHONE_STATE, OPSTR_READ_PHONE_STATE, "READ_PHONE_STATE")
+ .setPermission(Manifest.permission.READ_PHONE_STATE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ADD_VOICEMAIL, OPSTR_ADD_VOICEMAIL, "ADD_VOICEMAIL")
+ .setPermission(Manifest.permission.ADD_VOICEMAIL)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_USE_SIP, OPSTR_USE_SIP, "USE_SIP")
+ .setPermission(Manifest.permission.USE_SIP)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_PROCESS_OUTGOING_CALLS, OPSTR_PROCESS_OUTGOING_CALLS,
+ "PROCESS_OUTGOING_CALLS").setSwitchCode(OP_PROCESS_OUTGOING_CALLS)
+ .setPermission(Manifest.permission.PROCESS_OUTGOING_CALLS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_USE_FINGERPRINT, OPSTR_USE_FINGERPRINT, "USE_FINGERPRINT")
+ .setPermission(Manifest.permission.USE_FINGERPRINT)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_BODY_SENSORS, OPSTR_BODY_SENSORS, "BODY_SENSORS")
+ .setPermission(Manifest.permission.BODY_SENSORS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_CELL_BROADCASTS, OPSTR_READ_CELL_BROADCASTS,
+ "READ_CELL_BROADCASTS").setPermission(Manifest.permission.READ_CELL_BROADCASTS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_MOCK_LOCATION, OPSTR_MOCK_LOCATION, "MOCK_LOCATION")
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ new AppOpInfo.Builder(OP_READ_EXTERNAL_STORAGE, OPSTR_READ_EXTERNAL_STORAGE,
+ "READ_EXTERNAL_STORAGE").setPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_EXTERNAL_STORAGE, OPSTR_WRITE_EXTERNAL_STORAGE,
+ "WRITE_EXTERNAL_STORAGE").setPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_TURN_SCREEN_ON, OPSTR_TURN_SCREEN_ON, "TURN_SCREEN_ON")
+ .setPermission(Manifest.permission.TURN_SCREEN_ON)
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ new AppOpInfo.Builder(OP_GET_ACCOUNTS, OPSTR_GET_ACCOUNTS, "GET_ACCOUNTS")
+ .setPermission(Manifest.permission.GET_ACCOUNTS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RUN_IN_BACKGROUND, OPSTR_RUN_IN_BACKGROUND, "RUN_IN_BACKGROUND")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_AUDIO_ACCESSIBILITY_VOLUME, OPSTR_AUDIO_ACCESSIBILITY_VOLUME,
+ "AUDIO_ACCESSIBILITY_VOLUME")
+ .setRestriction(UserManager.DISALLOW_ADJUST_VOLUME)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_PHONE_NUMBERS, OPSTR_READ_PHONE_NUMBERS, "READ_PHONE_NUMBERS")
+ .setPermission(Manifest.permission.READ_PHONE_NUMBERS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_REQUEST_INSTALL_PACKAGES, OPSTR_REQUEST_INSTALL_PACKAGES,
+ "REQUEST_INSTALL_PACKAGES").setSwitchCode(OP_REQUEST_INSTALL_PACKAGES)
+ .setPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES).build(),
+ new AppOpInfo.Builder(OP_PICTURE_IN_PICTURE, OPSTR_PICTURE_IN_PICTURE, "PICTURE_IN_PICTURE")
+ .setSwitchCode(OP_PICTURE_IN_PICTURE).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_INSTANT_APP_START_FOREGROUND, OPSTR_INSTANT_APP_START_FOREGROUND,
+ "INSTANT_APP_START_FOREGROUND")
+ .setPermission(Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE).build(),
+ new AppOpInfo.Builder(OP_ANSWER_PHONE_CALLS, OPSTR_ANSWER_PHONE_CALLS, "ANSWER_PHONE_CALLS")
+ .setSwitchCode(OP_ANSWER_PHONE_CALLS)
+ .setPermission(Manifest.permission.ANSWER_PHONE_CALLS)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RUN_ANY_IN_BACKGROUND, OPSTR_RUN_ANY_IN_BACKGROUND,
+ "RUN_ANY_IN_BACKGROUND")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_CHANGE_WIFI_STATE, OPSTR_CHANGE_WIFI_STATE, "CHANGE_WIFI_STATE")
+ .setSwitchCode(OP_CHANGE_WIFI_STATE)
+ .setPermission(Manifest.permission.CHANGE_WIFI_STATE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_REQUEST_DELETE_PACKAGES, OPSTR_REQUEST_DELETE_PACKAGES,
+ "REQUEST_DELETE_PACKAGES")
+ .setPermission(Manifest.permission.REQUEST_DELETE_PACKAGES)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_BIND_ACCESSIBILITY_SERVICE, OPSTR_BIND_ACCESSIBILITY_SERVICE,
+ "BIND_ACCESSIBILITY_SERVICE")
+ .setPermission(Manifest.permission.BIND_ACCESSIBILITY_SERVICE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ACCEPT_HANDOVER, OPSTR_ACCEPT_HANDOVER, "ACCEPT_HANDOVER")
+ .setSwitchCode(OP_ACCEPT_HANDOVER)
+ .setPermission(Manifest.permission.ACCEPT_HANDOVER)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_MANAGE_IPSEC_TUNNELS, OPSTR_MANAGE_IPSEC_TUNNELS,
+ "MANAGE_IPSEC_TUNNELS")
+ .setPermission(Manifest.permission.MANAGE_IPSEC_TUNNELS)
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ new AppOpInfo.Builder(OP_START_FOREGROUND, OPSTR_START_FOREGROUND, "START_FOREGROUND")
+ .setPermission(Manifest.permission.FOREGROUND_SERVICE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_BLUETOOTH_SCAN, OPSTR_BLUETOOTH_SCAN, "BLUETOOTH_SCAN")
+ .setPermission(Manifest.permission.BLUETOOTH_SCAN)
+ .setAllowSystemRestrictionBypass(new RestrictionBypass(false, true, false))
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_USE_BIOMETRIC, OPSTR_USE_BIOMETRIC, "USE_BIOMETRIC")
+ .setPermission(Manifest.permission.USE_BIOMETRIC)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ACTIVITY_RECOGNITION, OPSTR_ACTIVITY_RECOGNITION,
+ "ACTIVITY_RECOGNITION")
+ .setPermission(Manifest.permission.ACTIVITY_RECOGNITION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_SMS_FINANCIAL_TRANSACTIONS, OPSTR_SMS_FINANCIAL_TRANSACTIONS,
+ "SMS_FINANCIAL_TRANSACTIONS")
+ .setPermission(Manifest.permission.SMS_FINANCIAL_TRANSACTIONS)
+ .setRestriction(UserManager.DISALLOW_SMS).build(),
+ new AppOpInfo.Builder(OP_READ_MEDIA_AUDIO, OPSTR_READ_MEDIA_AUDIO, "READ_MEDIA_AUDIO")
+ .setPermission(Manifest.permission.READ_MEDIA_AUDIO)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_MEDIA_AUDIO, OPSTR_WRITE_MEDIA_AUDIO, "WRITE_MEDIA_AUDIO")
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ new AppOpInfo.Builder(OP_READ_MEDIA_VIDEO, OPSTR_READ_MEDIA_VIDEO, "READ_MEDIA_VIDEO")
+ .setPermission(Manifest.permission.READ_MEDIA_VIDEO)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_MEDIA_VIDEO, OPSTR_WRITE_MEDIA_VIDEO, "WRITE_MEDIA_VIDEO")
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_READ_MEDIA_IMAGES, OPSTR_READ_MEDIA_IMAGES, "READ_MEDIA_IMAGES")
+ .setPermission(Manifest.permission.READ_MEDIA_IMAGES)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_WRITE_MEDIA_IMAGES, OPSTR_WRITE_MEDIA_IMAGES, "WRITE_MEDIA_IMAGES")
+ .setDefaultMode(AppOpsManager.MODE_ERRORED).setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_LEGACY_STORAGE, OPSTR_LEGACY_STORAGE, "LEGACY_STORAGE")
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_ACCESS_ACCESSIBILITY, OPSTR_ACCESS_ACCESSIBILITY,
+ "ACCESS_ACCESSIBILITY").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_READ_DEVICE_IDENTIFIERS, OPSTR_READ_DEVICE_IDENTIFIERS,
+ "READ_DEVICE_IDENTIFIERS").setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ new AppOpInfo.Builder(OP_ACCESS_MEDIA_LOCATION, OPSTR_ACCESS_MEDIA_LOCATION,
+ "ACCESS_MEDIA_LOCATION").setPermission(Manifest.permission.ACCESS_MEDIA_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_QUERY_ALL_PACKAGES, OPSTR_QUERY_ALL_PACKAGES, "QUERY_ALL_PACKAGES")
+ .build(),
+ new AppOpInfo.Builder(OP_MANAGE_EXTERNAL_STORAGE, OPSTR_MANAGE_EXTERNAL_STORAGE,
+ "MANAGE_EXTERNAL_STORAGE")
+ .setPermission(Manifest.permission.MANAGE_EXTERNAL_STORAGE).build(),
+ new AppOpInfo.Builder(OP_INTERACT_ACROSS_PROFILES, OPSTR_INTERACT_ACROSS_PROFILES,
+ "INTERACT_ACROSS_PROFILES")
+ .setPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES).build(),
+ new AppOpInfo.Builder(OP_ACTIVATE_PLATFORM_VPN, OPSTR_ACTIVATE_PLATFORM_VPN,
+ "ACTIVATE_PLATFORM_VPN").setDefaultMode(AppOpsManager.MODE_IGNORED).build(),
+ new AppOpInfo.Builder(OP_LOADER_USAGE_STATS, OPSTR_LOADER_USAGE_STATS, "LOADER_USAGE_STATS")
+ .setPermission(android.Manifest.permission.LOADER_USAGE_STATS).build(),
+ new AppOpInfo.Builder(OP_NONE, "", "").setDefaultMode(AppOpsManager.MODE_IGNORED).build(),
+ new AppOpInfo.Builder(OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+ OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, "AUTO_REVOKE_PERMISSIONS_IF_UNUSED")
+ .build(),
+ new AppOpInfo.Builder(OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
+ OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, "AUTO_REVOKE_MANAGED_BY_INSTALLER")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_NO_ISOLATED_STORAGE, OPSTR_NO_ISOLATED_STORAGE,
+ "NO_ISOLATED_STORAGE").setDefaultMode(AppOpsManager.MODE_ERRORED)
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_PHONE_CALL_MICROPHONE, OPSTR_PHONE_CALL_MICROPHONE,
+ "PHONE_CALL_MICROPHONE").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_PHONE_CALL_CAMERA, OPSTR_PHONE_CALL_CAMERA, "PHONE_CALL_CAMERA")
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECORD_AUDIO_HOTWORD, OPSTR_RECORD_AUDIO_HOTWORD,
+ "RECORD_AUDIO_HOTWORD").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_MANAGE_ONGOING_CALLS, OPSTR_MANAGE_ONGOING_CALLS,
+ "MANAGE_ONGOING_CALLS").setPermission(Manifest.permission.MANAGE_ONGOING_CALLS)
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_MANAGE_CREDENTIALS, OPSTR_MANAGE_CREDENTIALS, "MANAGE_CREDENTIALS")
+ .build(),
+ new AppOpInfo.Builder(OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
+ OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER")
+ .setPermission(Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER)
+ .setDisableReset(true).build(),
+ new AppOpInfo.Builder(OP_RECORD_AUDIO_OUTPUT, OPSTR_RECORD_AUDIO_OUTPUT,
+ "RECORD_AUDIO_OUTPUT").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_SCHEDULE_EXACT_ALARM, OPSTR_SCHEDULE_EXACT_ALARM,
+ "SCHEDULE_EXACT_ALARM").setPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
+ .build(),
+ new AppOpInfo.Builder(OP_FINE_LOCATION_SOURCE, OPSTR_FINE_LOCATION_SOURCE,
+ "FINE_LOCATION_SOURCE").setSwitchCode(OP_FINE_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_COARSE_LOCATION_SOURCE, OPSTR_COARSE_LOCATION_SOURCE,
+ "COARSE_LOCATION_SOURCE").setSwitchCode(OP_COARSE_LOCATION)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_MANAGE_MEDIA, OPSTR_MANAGE_MEDIA, "MANAGE_MEDIA")
+ .setPermission(Manifest.permission.MANAGE_MEDIA).build(),
+ new AppOpInfo.Builder(OP_BLUETOOTH_CONNECT, OPSTR_BLUETOOTH_CONNECT, "BLUETOOTH_CONNECT")
+ .setPermission(Manifest.permission.BLUETOOTH_CONNECT)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_UWB_RANGING, OPSTR_UWB_RANGING, "UWB_RANGING")
+ .setPermission(Manifest.permission.UWB_RANGING)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ACTIVITY_RECOGNITION_SOURCE, OPSTR_ACTIVITY_RECOGNITION_SOURCE,
+ "ACTIVITY_RECOGNITION_SOURCE")
+ .setSwitchCode(OP_ACTIVITY_RECOGNITION).setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .build(),
+ new AppOpInfo.Builder(OP_BLUETOOTH_ADVERTISE, OPSTR_BLUETOOTH_ADVERTISE,
+ "BLUETOOTH_ADVERTISE").setPermission(Manifest.permission.BLUETOOTH_ADVERTISE)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECORD_INCOMING_PHONE_AUDIO, OPSTR_RECORD_INCOMING_PHONE_AUDIO,
+ "RECORD_INCOMING_PHONE_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_NEARBY_WIFI_DEVICES, OPSTR_NEARBY_WIFI_DEVICES,
+ "NEARBY_WIFI_DEVICES").setPermission(Manifest.permission.NEARBY_WIFI_DEVICES)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ESTABLISH_VPN_SERVICE, OPSTR_ESTABLISH_VPN_SERVICE,
+ "ESTABLISH_VPN_SERVICE").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ESTABLISH_VPN_MANAGER, OPSTR_ESTABLISH_VPN_MANAGER,
+ "ESTABLISH_VPN_MANAGER").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_ACCESS_RESTRICTED_SETTINGS, OPSTR_ACCESS_RESTRICTED_SETTINGS,
+ "ACCESS_RESTRICTED_SETTINGS").setDefaultMode(AppOpsManager.MODE_ALLOWED)
+ .setDisableReset(true).setRestrictRead(true).build(),
+ new AppOpInfo.Builder(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+ "RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
};
/**
@@ -3101,46 +2316,18 @@
private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
static {
- if (sOpToSwitch.length != _NUM_OP) {
- throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length
+ if (sAppOpInfos.length != _NUM_OP) {
+ throw new IllegalStateException("mAppOpInfos length " + sAppOpInfos.length
+ " should be " + _NUM_OP);
}
- if (sOpToString.length != _NUM_OP) {
- throw new IllegalStateException("sOpToString length " + sOpToString.length
- + " should be " + _NUM_OP);
- }
- if (sOpNames.length != _NUM_OP) {
- throw new IllegalStateException("sOpNames length " + sOpNames.length
- + " should be " + _NUM_OP);
- }
- if (sOpPerms.length != _NUM_OP) {
- throw new IllegalStateException("sOpPerms length " + sOpPerms.length
- + " should be " + _NUM_OP);
- }
- if (sOpDefaultMode.length != _NUM_OP) {
- throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length
- + " should be " + _NUM_OP);
- }
- if (sOpDisableReset.length != _NUM_OP) {
- throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
- + " should be " + _NUM_OP);
- }
- if (sOpRestrictions.length != _NUM_OP) {
- throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length
- + " should be " + _NUM_OP);
- }
- if (sOpAllowSystemRestrictionBypass.length != _NUM_OP) {
- throw new IllegalStateException("sOpAllowSYstemRestrictionsBypass length "
- + sOpRestrictions.length + " should be " + _NUM_OP);
- }
for (int i=0; i<_NUM_OP; i++) {
- if (sOpToString[i] != null) {
- sOpStrToOp.put(sOpToString[i], i);
+ if (sAppOpInfos[i].name != null) {
+ sOpStrToOp.put(sAppOpInfos[i].name, i);
}
}
for (int op : RUNTIME_AND_APPOP_PERMISSIONS_OPS) {
- if (sOpPerms[op] != null) {
- sPermToOp.put(sOpPerms[op], op);
+ if (sAppOpInfos[op].permission != null) {
+ sPermToOp.put(sAppOpInfos[op].permission, op);
}
}
@@ -3170,7 +2357,7 @@
*/
@UnsupportedAppUsage
public static int opToSwitch(int op) {
- return sOpToSwitch[op];
+ return sAppOpInfos[op].switchCode;
}
/**
@@ -3180,7 +2367,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static String opToName(int op) {
if (op == OP_NONE) return "NONE";
- return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
+ return op < sAppOpInfos.length ? sAppOpInfos[op].simpleName : ("Unknown(" + op + ")");
}
/**
@@ -3189,15 +2376,15 @@
* @hide
*/
public static @NonNull String opToPublicName(int op) {
- return sOpToString[op];
+ return sAppOpInfos[op].name;
}
/**
* @hide
*/
public static int strDebugOpToOp(String op) {
- for (int i=0; i<sOpNames.length; i++) {
- if (sOpNames[i].equals(op)) {
+ for (int i = 0; i < sAppOpInfos.length; i++) {
+ if (sAppOpInfos[i].simpleName.equals(op)) {
return i;
}
}
@@ -3211,7 +2398,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
public static String opToPermission(int op) {
- return sOpPerms[op];
+ return sAppOpInfos[op].permission;
}
/**
@@ -3232,7 +2419,7 @@
* @hide
*/
public static String opToRestriction(int op) {
- return sOpRestrictions[op];
+ return sAppOpInfos[op].restriction;
}
/**
@@ -3254,7 +2441,7 @@
* @hide
*/
public static RestrictionBypass opAllowSystemBypassRestriction(int op) {
- return sOpAllowSystemRestrictionBypass[op];
+ return sAppOpInfos[op].allowSystemRestrictionBypass;
}
/**
@@ -3262,7 +2449,7 @@
* @hide
*/
public static @Mode int opToDefaultMode(int op) {
- return sOpDefaultMode[op];
+ return sAppOpInfos[op].defaultMode;
}
/**
@@ -3295,7 +2482,7 @@
* @hide
*/
public static boolean opRestrictsRead(int op) {
- return sOpRestrictRead[op];
+ return sAppOpInfos[op].restrictRead;
}
/**
@@ -3303,7 +2490,7 @@
* @hide
*/
public static boolean opAllowsReset(int op) {
- return !sOpDisableReset[op];
+ return !sAppOpInfos[op].disableReset;
}
/**
@@ -4436,7 +3623,7 @@
* @return This entry's op string name, such as {@link #OPSTR_COARSE_LOCATION}.
*/
public @NonNull String getOpStr() {
- return sOpToString[mOp];
+ return sAppOpInfos[mOp].name;
}
/**
@@ -6553,7 +5740,7 @@
if (mHistoricalOps == null) {
mHistoricalOps = new ArrayMap<>();
}
- final String opStr = sOpToString[opCode];
+ final String opStr = sAppOpInfos[opCode].name;
HistoricalOp op = mHistoricalOps.get(opStr);
if (op == null) {
op = new HistoricalOp(opCode);
@@ -6898,7 +6085,7 @@
* @return The op name.
*/
public @NonNull String getOpName() {
- return sOpToString[mOp];
+ return sAppOpInfos[mOp].name;
}
/** @hide */
@@ -7912,7 +7099,7 @@
if (opCode == null) {
return null;
}
- return sOpToString[opCode];
+ return sAppOpInfos[opCode].name;
}
/**
@@ -8007,8 +7194,8 @@
if (callback instanceof OnOpChangedInternalListener) {
((OnOpChangedInternalListener)callback).onOpChanged(op, packageName);
}
- if (sOpToString[op] != null) {
- callback.onOpChanged(sOpToString[op], packageName);
+ if (sAppOpInfos[op].name != null) {
+ callback.onOpChanged(sAppOpInfos[op].name, packageName);
}
}
};
@@ -8096,8 +7283,8 @@
((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op,
uid, packageName, active);
}
- if (sOpToString[op] != null) {
- callback.onOpActiveChanged(sOpToString[op], uid, packageName,
+ if (sAppOpInfos[op].name != null) {
+ callback.onOpActiveChanged(sAppOpInfos[op].name, uid, packageName,
attributionTag, active, attributionFlags, attributionChainId);
}
});
@@ -8273,7 +7460,8 @@
}
private String buildSecurityExceptionMsg(int op, int uid, String packageName) {
- return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
+ return packageName + " from uid " + uid + " not allowed to perform " +
+ sAppOpInfos[op].simpleName;
}
/**
@@ -8578,9 +7766,9 @@
public int noteProxyOp(int op, @Nullable String proxiedPackageName, int proxiedUid,
@Nullable String proxiedAttributionTag, @Nullable String message) {
return noteProxyOp(op, new AttributionSource(mContext.getAttributionSource(),
- new AttributionSource(proxiedUid, /*pid*/ -1, proxiedPackageName,
- proxiedAttributionTag, mContext.getAttributionSource().getToken())),
- message, /*skipProxyOperation*/ false);
+ new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag,
+ mContext.getAttributionSource().getToken())), message,
+ /*skipProxyOperation*/ false);
}
/**
@@ -8633,7 +7821,7 @@
+ attributionSource.getUid() + " or calling package "
+ attributionSource.getNextPackageName() + " from uid "
+ attributionSource.getNextUid() + " not allowed to perform "
- + sOpNames[op]);
+ + sAppOpInfos[op].simpleName);
}
return mode;
}
@@ -8664,7 +7852,7 @@
public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName,
int proxiedUid, @Nullable String proxiedAttributionTag, @Nullable String message) {
return noteProxyOpNoThrow(strOpToOp(op), new AttributionSource(
- mContext.getAttributionSource(), new AttributionSource(proxiedUid, /*pid*/ -1,
+ mContext.getAttributionSource(), new AttributionSource(proxiedUid,
proxiedPackageName, proxiedAttributionTag, mContext.getAttributionSource()
.getToken())), message,/*skipProxyOperation*/ false);
}
@@ -9076,9 +8264,9 @@
public int startProxyOp(@NonNull String op, int proxiedUid, @NonNull String proxiedPackageName,
@Nullable String proxiedAttributionTag, @Nullable String message) {
return startProxyOp(op, new AttributionSource(mContext.getAttributionSource(),
- new AttributionSource(proxiedUid, /*pid*/ -1, proxiedPackageName,
- proxiedAttributionTag, mContext.getAttributionSource().getToken())),
- message, /*skipProxyOperation*/ false);
+ new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag,
+ mContext.getAttributionSource().getToken())), message,
+ /*skipProxyOperation*/ false);
}
/**
@@ -9124,7 +8312,7 @@
@Nullable String message) {
return startProxyOpNoThrow(AppOpsManager.strOpToOp(op), new AttributionSource(
mContext.getAttributionSource(), new AttributionSource(proxiedUid,
- /*pid*/ -1, proxiedPackageName, proxiedAttributionTag,
+ proxiedPackageName, proxiedAttributionTag,
mContext.getAttributionSource().getToken())), message,
/*skipProxyOperation*/ false);
}
@@ -9270,9 +8458,8 @@
public void finishProxyOp(@NonNull String op, int proxiedUid,
@NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag) {
finishProxyOp(op, new AttributionSource(mContext.getAttributionSource(),
- new AttributionSource(proxiedUid, /*pid*/ -1, proxiedPackageName,
- proxiedAttributionTag, mContext.getAttributionSource().getToken())),
- /*skipProxyOperation*/ false);
+ new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag,
+ mContext.getAttributionSource().getToken())), /*skipProxyOperation*/ false);
}
/**
@@ -10085,10 +9272,13 @@
*/
@SystemApi
public static String[] getOpStrs() {
- return Arrays.copyOf(sOpToString, sOpToString.length);
+ String[] opStrs = new String[sAppOpInfos.length];
+ for(int i = 0; i < sAppOpInfos.length; i++) {
+ opStrs[i] = sAppOpInfos[i].name;
+ }
+ return opStrs;
}
-
/**
* @return number of App ops
* @hide
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c1a2183..4c7bc6d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3227,9 +3227,7 @@
@Nullable AttributionSource nextAttributionSource,
@Nullable Set<String> renouncedPermissions) {
AttributionSource attributionSource = new AttributionSource(Process.myUid(),
- Process.myPid(), mOpPackageName, attributionTag,
- (renouncedPermissions != null) ? renouncedPermissions.toArray(new String[0]) : null,
- nextAttributionSource);
+ mOpPackageName, attributionTag, renouncedPermissions, nextAttributionSource);
// If we want to access protected data on behalf of another app we need to
// tell the OS that we opt in to participate in the attribution chain.
if (nextAttributionSource != null) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 0e89b25..b9ad595 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -124,8 +124,13 @@
/**
* The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
* limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
+ /**
+ * @hide
+ */
+ public static final int MAX_VIBRATION_LENGTH = 1000;
private static final String TAG_CHANNEL = "channel";
private static final String ATT_NAME = "name";
@@ -283,17 +288,17 @@
*/
protected NotificationChannel(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
if (in.readByte() != 0) {
- mName = in.readString();
+ mName = getTrimmedString(in.readString());
} else {
mName = null;
}
if (in.readByte() != 0) {
- mDesc = in.readString();
+ mDesc = getTrimmedString(in.readString());
} else {
mDesc = null;
}
@@ -302,18 +307,22 @@
mLockscreenVisibility = in.readInt();
if (in.readByte() != 0) {
mSound = Uri.CREATOR.createFromParcel(in);
+ mSound = Uri.parse(getTrimmedString(mSound.toString()));
} else {
mSound = null;
}
mLights = in.readByte() != 0;
mVibration = in.createLongArray();
+ if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) {
+ mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH);
+ }
mUserLockedFields = in.readInt();
mFgServiceShown = in.readByte() != 0;
mVibrationEnabled = in.readByte() != 0;
mShowBadge = in.readByte() != 0;
mDeleted = in.readByte() != 0;
if (in.readByte() != 0) {
- mGroup = in.readString();
+ mGroup = getTrimmedString(in.readString());
} else {
mGroup = null;
}
@@ -322,8 +331,8 @@
mBlockableSystem = in.readBoolean();
mAllowBubbles = in.readInt();
mOriginalImportance = in.readInt();
- mParentId = in.readString();
- mConversationId = in.readString();
+ mParentId = getTrimmedString(in.readString());
+ mConversationId = getTrimmedString(in.readString());
mDemoted = in.readBoolean();
mImportantConvo = in.readBoolean();
mDeletedTime = in.readLong();
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index f97415c..807bd57 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -20,6 +20,7 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
+import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -43,8 +44,9 @@
/**
* The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at
* this limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
private static final String TAG_GROUP = "channelGroup";
private static final String ATT_NAME = "name";
@@ -66,7 +68,7 @@
private CharSequence mName;
private String mDescription;
private boolean mBlocked;
- private List<NotificationChannel> mChannels = new ArrayList<>();
+ private ParceledListSlice<NotificationChannel> mChannels;
// Bitwise representation of fields that have been changed by the user
private int mUserLockedFields;
@@ -90,17 +92,19 @@
*/
protected NotificationChannelGroup(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mName = getTrimmedString(mName.toString());
if (in.readByte() != 0) {
- mDescription = in.readString();
+ mDescription = getTrimmedString(in.readString());
} else {
mDescription = null;
}
- in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
+ mChannels = in.readParcelable(
+ NotificationChannelGroup.class.getClassLoader(), ParceledListSlice.class);
mBlocked = in.readBoolean();
mUserLockedFields = in.readInt();
}
@@ -120,14 +124,14 @@
} else {
dest.writeByte((byte) 0);
}
- TextUtils.writeToParcel(mName, dest, flags);
+ TextUtils.writeToParcel(mName.toString(), dest, flags);
if (mDescription != null) {
dest.writeByte((byte) 1);
dest.writeString(mDescription);
} else {
dest.writeByte((byte) 0);
}
- dest.writeParcelableList(mChannels, flags);
+ dest.writeParcelable(mChannels, flags);
dest.writeBoolean(mBlocked);
dest.writeInt(mUserLockedFields);
}
@@ -157,7 +161,7 @@
* Returns the list of channels that belong to this group
*/
public List<NotificationChannel> getChannels() {
- return mChannels;
+ return mChannels == null ? new ArrayList<>() : mChannels.getList();
}
/**
@@ -191,15 +195,8 @@
/**
* @hide
*/
- public void addChannel(NotificationChannel channel) {
- mChannels.add(channel);
- }
-
- /**
- * @hide
- */
public void setChannels(List<NotificationChannel> channels) {
- mChannels = channels;
+ mChannels = new ParceledListSlice<>(channels);
}
/**
@@ -334,7 +331,7 @@
proto.write(NotificationChannelGroupProto.NAME, mName.toString());
proto.write(NotificationChannelGroupProto.DESCRIPTION, mDescription);
proto.write(NotificationChannelGroupProto.IS_BLOCKED, mBlocked);
- for (NotificationChannel channel : mChannels) {
+ for (NotificationChannel channel : mChannels.getList()) {
channel.dumpDebug(proto, NotificationChannelGroupProto.CHANNELS);
}
proto.end(token);
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 272e235..3f2fa21 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -100,28 +100,22 @@
@TestApi
public AttributionSource(int uid, @Nullable String packageName,
@Nullable String attributionTag) {
- this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken);
- }
-
- /** @hide */
- public AttributionSource(int uid, int pid, @Nullable String packageName,
- @Nullable String attributionTag) {
- this(uid, pid, packageName, attributionTag, sDefaultToken);
+ this(uid, packageName, attributionTag, sDefaultToken);
}
/** @hide */
@TestApi
public AttributionSource(int uid, @Nullable String packageName,
@Nullable String attributionTag, @NonNull IBinder token) {
- this(uid, Process.INVALID_PID, packageName, attributionTag, token,
- /*renouncedPermissions*/ null, /*next*/ null);
+ this(uid, packageName, attributionTag, token, /*renouncedPermissions*/ null,
+ /*next*/ null);
}
/** @hide */
- public AttributionSource(int uid, int pid, @Nullable String packageName,
- @Nullable String attributionTag, @NonNull IBinder token) {
- this(uid, pid, packageName, attributionTag, token, /*renouncedPermissions*/ null,
- /*next*/ null);
+ public AttributionSource(int uid, @Nullable String packageName,
+ @Nullable String attributionTag, @NonNull IBinder token,
+ @Nullable AttributionSource next) {
+ this(uid, packageName, attributionTag, token, /*renouncedPermissions*/ null, next);
}
/** @hide */
@@ -129,33 +123,26 @@
public AttributionSource(int uid, @Nullable String packageName,
@Nullable String attributionTag, @Nullable Set<String> renouncedPermissions,
@Nullable AttributionSource next) {
- this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken,
- (renouncedPermissions != null)
- ? renouncedPermissions.toArray(new String[0]) : null, /*next*/ next);
+ this(uid, packageName, attributionTag, (renouncedPermissions != null)
+ ? renouncedPermissions.toArray(new String[0]) : null, next);
}
/** @hide */
public AttributionSource(@NonNull AttributionSource current, @Nullable AttributionSource next) {
- this(current.getUid(), current.getPid(), current.getPackageName(),
- current.getAttributionTag(), current.getToken(),
- current.mAttributionSourceState.renouncedPermissions, next);
+ this(current.getUid(), current.getPackageName(), current.getAttributionTag(),
+ current.getToken(), current.mAttributionSourceState.renouncedPermissions, next);
}
- /** @hide */
- public AttributionSource(int uid, int pid, @Nullable String packageName,
- @Nullable String attributionTag, @Nullable String[] renouncedPermissions,
- @Nullable AttributionSource next) {
- this(uid, pid, packageName, attributionTag, sDefaultToken, renouncedPermissions, next);
+ AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag,
+ @Nullable String[] renouncedPermissions, @Nullable AttributionSource next) {
+ this(uid, packageName, attributionTag, sDefaultToken, renouncedPermissions, next);
}
- /** @hide */
- public AttributionSource(int uid, int pid, @Nullable String packageName,
- @Nullable String attributionTag, @NonNull IBinder token,
- @Nullable String[] renouncedPermissions,
+ AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag,
+ @NonNull IBinder token, @Nullable String[] renouncedPermissions,
@Nullable AttributionSource next) {
mAttributionSourceState = new AttributionSourceState();
mAttributionSourceState.uid = uid;
- mAttributionSourceState.pid = pid;
mAttributionSourceState.token = token;
mAttributionSourceState.packageName = packageName;
mAttributionSourceState.attributionTag = attributionTag;
@@ -169,17 +156,7 @@
// Since we just unpacked this object as part of it transiting a Binder
// call, this is the perfect time to enforce that its UID and PID can be trusted
- enforceCallingUid();
-
- // If this object is being constructed as part of a oneway Binder call, getCallingPid will
- // return 0 instead of the true PID. In that case, invalidate the PID by setting it to
- // INVALID_PID (-1).
- final int callingPid = Binder.getCallingPid();
- if (callingPid == 0) {
- mAttributionSourceState.pid = Process.INVALID_PID;
- }
-
- enforceCallingPid();
+ enforceCallingUidAndPid();
}
/** @hide */
@@ -189,19 +166,19 @@
/** @hide */
public AttributionSource withNextAttributionSource(@Nullable AttributionSource next) {
- return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
- getToken(), mAttributionSourceState.renouncedPermissions, next);
+ return new AttributionSource(getUid(), getPackageName(), getAttributionTag(),
+ mAttributionSourceState.renouncedPermissions, next);
}
/** @hide */
public AttributionSource withPackageName(@Nullable String packageName) {
- return new AttributionSource(getUid(), getPid(), packageName, getAttributionTag(),
- getToken(), mAttributionSourceState.renouncedPermissions, getNext());
+ return new AttributionSource(getUid(), packageName, getAttributionTag(),
+ mAttributionSourceState.renouncedPermissions, getNext());
}
/** @hide */
public AttributionSource withToken(@NonNull Binder token) {
- return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
+ return new AttributionSource(getUid(), getPackageName(), getAttributionTag(),
token, mAttributionSourceState.renouncedPermissions, getNext());
}
@@ -245,7 +222,6 @@
}
try {
return new AttributionSource.Builder(uid)
- .setPid(Process.myPid())
.setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0])
.build();
} catch (Exception ignored) {
@@ -283,6 +259,18 @@
}
/**
+ * If you are handling an IPC and you don't trust the caller you need to validate whether the
+ * attribution source is one for the calling app to prevent the caller to pass you a source from
+ * another app without including themselves in the attribution chain.
+ *
+ * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
+ */
+ private void enforceCallingUidAndPid() {
+ enforceCallingUid();
+ enforceCallingPid();
+ }
+
+ /**
* If you are handling an IPC and you don't trust the caller you need to validate
* whether the attribution source is one for the calling app to prevent the caller
* to pass you a source from another app without including themselves in the
@@ -318,10 +306,7 @@
}
/**
- * Validate that the pid being claimed for the calling app is not spoofed.
- *
- * Note that the PID may be unavailable, for example if we're in a oneway Binder call. In this
- * case, calling enforceCallingPid is guaranteed to fail. The caller should anticipate this.
+ * Validate that the pid being claimed for the calling app is not spoofed
*
* @throws SecurityException if the attribution source cannot be trusted to be from the caller.
* @hide
@@ -329,12 +314,8 @@
@TestApi
public void enforceCallingPid() {
if (!checkCallingPid()) {
- if (Binder.getCallingPid() == 0) {
- throw new SecurityException("Calling pid unavailable due to oneway Binder call.");
- } else {
- throw new SecurityException("Calling pid: " + Binder.getCallingPid()
- + " doesn't match source pid: " + mAttributionSourceState.pid);
- }
+ throw new SecurityException("Calling pid: " + Binder.getCallingPid()
+ + " doesn't match source pid: " + mAttributionSourceState.pid);
}
}
@@ -345,8 +326,7 @@
*/
private boolean checkCallingPid() {
final int callingPid = Binder.getCallingPid();
- if (mAttributionSourceState.pid != Process.INVALID_PID
- && callingPid != mAttributionSourceState.pid) {
+ if (mAttributionSourceState.pid != -1 && callingPid != mAttributionSourceState.pid) {
return false;
}
return true;
@@ -463,13 +443,6 @@
}
/**
- * The PID that is accessing the permission protected data.
- */
- public int getPid() {
- return mAttributionSourceState.pid;
- }
-
- /**
* The package that is accessing the permission protected data.
*/
public @Nullable String getPackageName() {
@@ -577,7 +550,6 @@
throw new IllegalArgumentException("current AttributionSource can not be null");
}
mAttributionSourceState.uid = current.getUid();
- mAttributionSourceState.pid = current.getPid();
mAttributionSourceState.packageName = current.getPackageName();
mAttributionSourceState.attributionTag = current.getAttributionTag();
mAttributionSourceState.token = current.getToken();
@@ -586,24 +558,11 @@
}
/**
- * The PID of the process that is accessing the permission protected data.
- *
- * If not called, pid will default to Process.INVALID_PID (-1). This indicates that the PID
- * data is missing. Supplying a PID is not required, but recommended when accessible.
- */
- public @NonNull Builder setPid(int value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mAttributionSourceState.pid = value;
- return this;
- }
-
- /**
* The package that is accessing the permission protected data.
*/
public @NonNull Builder setPackageName(@Nullable String value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x4;
+ mBuilderFieldsSet |= 0x2;
mAttributionSourceState.packageName = value;
return this;
}
@@ -613,7 +572,7 @@
*/
public @NonNull Builder setAttributionTag(@Nullable String value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x8;
+ mBuilderFieldsSet |= 0x4;
mAttributionSourceState.attributionTag = value;
return this;
}
@@ -646,7 +605,7 @@
@RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
public @NonNull Builder setRenouncedPermissions(@Nullable Set<String> value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x10;
+ mBuilderFieldsSet |= 0x8;
mAttributionSourceState.renouncedPermissions = (value != null)
? value.toArray(new String[0]) : null;
return this;
@@ -657,7 +616,7 @@
*/
public @NonNull Builder setNext(@Nullable AttributionSource value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x20;
+ mBuilderFieldsSet |= 0x10;
mAttributionSourceState.next = (value != null) ? new AttributionSourceState[]
{value.mAttributionSourceState} : mAttributionSourceState.next;
return this;
@@ -669,18 +628,15 @@
mBuilderFieldsSet |= 0x40; // Mark builder used
if ((mBuilderFieldsSet & 0x2) == 0) {
- mAttributionSourceState.pid = Process.INVALID_PID;
- }
- if ((mBuilderFieldsSet & 0x4) == 0) {
mAttributionSourceState.packageName = null;
}
- if ((mBuilderFieldsSet & 0x8) == 0) {
+ if ((mBuilderFieldsSet & 0x4) == 0) {
mAttributionSourceState.attributionTag = null;
}
- if ((mBuilderFieldsSet & 0x10) == 0) {
+ if ((mBuilderFieldsSet & 0x8) == 0) {
mAttributionSourceState.renouncedPermissions = null;
}
- if ((mBuilderFieldsSet & 0x20) == 0) {
+ if ((mBuilderFieldsSet & 0x10) == 0) {
mAttributionSourceState.next = null;
}
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 0e3217d..8d3452e 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -152,7 +152,7 @@
@NonNull String permission, int pid, int uid, @Nullable String packageName,
@Nullable String attributionTag, @Nullable String message, boolean startDataDelivery) {
return checkPermissionForDataDelivery(context, permission, pid, new AttributionSource(uid,
- pid, packageName, attributionTag), message, startDataDelivery);
+ packageName, attributionTag), message, startDataDelivery);
}
/**
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
index be57372..d6f191e 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
@@ -37,6 +37,7 @@
import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
import android.os.PersistableBundle;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.vcn.util.PersistableBundleUtils;
@@ -58,6 +59,8 @@
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
public final class IkeSessionParamsUtils {
+ private static final String TAG = IkeSessionParamsUtils.class.getSimpleName();
+
private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY";
private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY";
@@ -72,6 +75,13 @@
private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY";
private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY";
+ // TODO: b/243181760 Use the IKE API when they are exposed
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7;
+
private static final Set<Integer> IKE_OPTIONS = new ArraySet<>();
static {
@@ -80,6 +90,26 @@
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE);
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500);
IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT);
+ IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY);
+ IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION);
+ IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES);
+ }
+
+ /**
+ * Check if an IKE option is supported in the IPsec module installed on the device
+ *
+ * <p>This method ensures caller to safely access options that are added between dessert
+ * releases.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static boolean isIkeOptionValid(int option) {
+ try {
+ new IkeSessionParams.Builder().addIkeOption(option);
+ return true;
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Option not supported; discarding: " + option);
+ return false;
+ }
}
/** Serializes an IkeSessionParams to a PersistableBundle. */
@@ -130,7 +160,7 @@
// IKE_OPTION is defined in IKE module and added in the IkeSessionParams
final List<Integer> enabledIkeOptions = new ArrayList<>();
for (int option : IKE_OPTIONS) {
- if (params.hasIkeOption(option)) {
+ if (isIkeOptionValid(option) && params.hasIkeOption(option)) {
enabledIkeOptions.add(option);
}
}
@@ -205,12 +235,16 @@
// Clear IKE Options that are by default enabled
for (int option : IKE_OPTIONS) {
- builder.removeIkeOption(option);
+ if (isIkeOptionValid(option)) {
+ builder.removeIkeOption(option);
+ }
}
final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY);
for (int option : optionArray) {
- builder.addIkeOption(option);
+ if (isIkeOptionValid(option)) {
+ builder.addIkeOption(option);
+ }
}
return builder.build();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 62ee408..fa6b118 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -76,6 +76,7 @@
String getUserAccount(int userId);
void setUserAccount(int userId, String accountName);
long getUserCreationTime(int userId);
+ boolean isUserSwitcherEnabled(int mUserId);
boolean isRestricted(int userId);
boolean canHaveRestrictedProfile(int userId);
int getUserSerialNumber(int userId);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 095d53e..14082f3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -364,11 +364,6 @@
public static final int LAST_APPLICATION_CACHE_GID = 29999;
/**
- * An invalid PID value.
- */
- public static final int INVALID_PID = -1;
-
- /**
* Standard priority of application threads.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ef04f64..ca0af2c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -5246,23 +5246,13 @@
})
@UserHandleAware
public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable) {
- if (!supportsMultipleUsers()) {
- return false;
- }
- if (hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId)) {
- return false;
- }
- // If Demo Mode is on, don't show user switcher
- if (isDeviceInDemoMode(mContext)) {
- return false;
- }
- // Check the Settings.Global.USER_SWITCHER_ENABLED that the user can toggle on/off.
- final boolean userSwitcherSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.USER_SWITCHER_ENABLED,
- Resources.getSystem().getBoolean(R.bool.config_showUserSwitcherByDefault) ? 1 : 0)
- != 0;
- if (!userSwitcherSettingOn) {
- return false;
+
+ try {
+ if (!mService.isUserSwitcherEnabled(mUserId)) {
+ return false;
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
// The feature is enabled. But is it worth showing?
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e67b67d..8a50e79 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10661,6 +10661,13 @@
public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption";
/**
+ * Whether to enable media controls on lock screen.
+ * When enabled, media controls will appear on lock screen.
+ * @hide
+ */
+ public static final String MEDIA_CONTROLS_LOCK_SCREEN = "media_controls_lock_screen";
+
+ /**
* Controls whether contextual suggestions can be shown in the media controls.
* @hide
*/
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9890614..b59cf7f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5872,4 +5872,10 @@
<!-- The number of tasks to scan to get the visibility of Home -->
<integer name="config_maxScanTasksForHomeVisibility">10</integer>
+
+ <!-- Device state that corresponds to rear display mode, feature provided
+ through Jetpack WindowManager
+ TODO(b/236022708) Move rear display state to device state config file
+ -->
+ <integer name="config_deviceStateRearDisplay">-1</integer>
</resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index e9b42d3..78ec145 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -23,7 +23,7 @@
<item>ak-GH</item> <!-- Akan (Ghana) -->
<item>am-ET</item> <!-- Amharic (Ethiopia) -->
<item>ar-AE</item> <!-- Arabic (United Arab Emirates) -->
- <item>ar-AE-u-nu-latn</item> <!-- Arabic (United Arab Emirates, Western Digits) -->
+ <item>ar-AE-u-nu-arab</item> <!-- Arabic (United Arab Emirates, Arabic Digits) -->
<item>ar-BH</item> <!-- Arabic (Bahrain) -->
<item>ar-BH-u-nu-latn</item> <!-- Arabic (Bahrain, Western Digits) -->
<item>ar-DJ</item> <!-- Arabic (Djibouti) -->
@@ -190,6 +190,7 @@
<item>en-MS</item> <!-- English (Montserrat) -->
<item>en-MT</item> <!-- English (Malta) -->
<item>en-MU</item> <!-- English (Mauritius) -->
+ <item>en-MV</item> <!-- English (Maldives) -->
<item>en-MW</item> <!-- English (Malawi) -->
<item>en-MY</item> <!-- English (Malaysia) -->
<item>en-NA</item> <!-- English (Namibia) -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0654fff..d60fc20 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4830,6 +4830,7 @@
<java-symbol type="drawable" name="ic_swap_horiz" />
<java-symbol type="array" name="config_deviceStatesAvailableForAppRequests" />
<java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
+ <java-symbol type="integer" name="config_deviceStateRearDisplay"/>
<!-- For app language picker -->
<java-symbol type="string" name="system_locale_title" />
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
new file mode 100644
index 0000000..2a3da05
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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 android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelGroupTest {
+ private final String CLASS = "android.app.NotificationChannelGroup";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName");
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(group, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(group, longString);
+ Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription");
+ mDescription.setAccessible(true);
+ mDescription.set(group, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ group.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup fromParcel =
+ NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ }
+}
diff --git a/core/tests/coretests/src/android/app/NotificationChannelTest.java b/core/tests/coretests/src/android/app/NotificationChannelTest.java
new file mode 100644
index 0000000..647bfe8
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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 android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelTest {
+ private final String CLASS = "android.app.NotificationChannel";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(channel, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(channel, longString);
+ Field mDesc = Class.forName(CLASS).getDeclaredField("mDesc");
+ mDesc.setAccessible(true);
+ mDesc.set(channel, longString);
+ Field mParentId = Class.forName(CLASS).getDeclaredField("mParentId");
+ mParentId.setAccessible(true);
+ mParentId.set(channel, longString);
+ Field mGroup = Class.forName(CLASS).getDeclaredField("mGroup");
+ mGroup.setAccessible(true);
+ mGroup.set(channel, longString);
+ Field mConversationId = Class.forName(CLASS).getDeclaredField("mConversationId");
+ mConversationId.setAccessible(true);
+ mConversationId.set(channel, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getParentChannelId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getGroup().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getConversationId().length());
+ }
+
+ @Test
+ public void testLongAlertFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ channel.setSound(Uri.parse("content://" + Strings.repeat("A",65536)),
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channel.setVibrationPattern(new long[65550/2]);
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_VIBRATION_LENGTH,
+ fromParcel.getVibrationPattern().length);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getSound().toString().length());
+ }
+}
diff --git a/core/tests/coretests/src/android/hardware/input/OWNERS b/core/tests/coretests/src/android/hardware/input/OWNERS
new file mode 100644
index 0000000..3f8a602
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/OWNERS
@@ -0,0 +1,2 @@
+include /core/java/android/hardware/input/OWNERS
+
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index b341a4e..c93b733 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -26,10 +26,21 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
UNKNOWN,
+ /**
+ * Since some APIs accept either ImageFormat or PixelFormat (and the two
+ * enums do not overlap since they're both partial versions of the
+ * internal format enum), add PixelFormat values here so linting
+ * tools won't complain when method arguments annotated with
+ * ImageFormat are provided with PixelFormat values.
+ */
+ PixelFormat.RGBA_8888,
+ PixelFormat.RGBX_8888,
+ PixelFormat.RGB_888,
RGB_565,
YV12,
Y8,
Y16,
+ YCBCR_P010,
NV16,
NV21,
YUY2,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index bdf703c..7e9c418 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -20,11 +20,14 @@
import android.content.Context;
import androidx.annotation.NonNull;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.area.WindowAreaComponentImpl;
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
import androidx.window.extensions.embedding.SplitController;
import androidx.window.extensions.layout.WindowLayoutComponent;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
+
/**
* The reference implementation of {@link WindowExtensions} that implements the initial API version.
*/
@@ -33,10 +36,12 @@
private final Object mLock = new Object();
private volatile WindowLayoutComponent mWindowLayoutComponent;
private volatile SplitController mSplitController;
+ private volatile WindowAreaComponent mWindowAreaComponent;
+ // TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return 1;
+ return 2;
}
/**
@@ -75,4 +80,23 @@
}
return mSplitController;
}
+
+ /**
+ * Returns a reference implementation of {@link WindowAreaComponent} if available,
+ * {@code null} otherwise. The implementation must match the API level reported in
+ * {@link WindowExtensions#getWindowAreaComponent()}.
+ * @return {@link WindowAreaComponent} OEM implementation.
+ */
+ public WindowAreaComponent getWindowAreaComponent() {
+ if (mWindowAreaComponent == null) {
+ synchronized (mLock) {
+ if (mWindowAreaComponent == null) {
+ Context context = ActivityThread.currentApplication();
+ mWindowAreaComponent =
+ new WindowAreaComponentImpl(context);
+ }
+ }
+ }
+ return mWindowAreaComponent;
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
new file mode 100644
index 0000000..3adae70
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.area;
+
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Reference implementation of androidx.window.extensions.area OEM interface for use with
+ * WindowManager Jetpack.
+ *
+ * This component currently supports Rear Display mode with the ability to add and remove
+ * status listeners for this mode.
+ *
+ * The public methods in this class are thread-safe.
+ **/
+public class WindowAreaComponentImpl implements WindowAreaComponent,
+ DeviceStateManager.DeviceStateCallback {
+
+ private final Object mLock = new Object();
+
+ private final DeviceStateManager mDeviceStateManager;
+ private final Executor mExecutor;
+
+ @GuardedBy("mLock")
+ private final ArraySet<Consumer<Integer>> mRearDisplayStatusListeners = new ArraySet<>();
+ private final int mRearDisplayState;
+ @WindowAreaSessionState
+ private int mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE;
+
+ @GuardedBy("mLock")
+ private int mCurrentDeviceState = INVALID_DEVICE_STATE;
+ @GuardedBy("mLock")
+ private int mCurrentDeviceBaseState = INVALID_DEVICE_STATE;
+ @GuardedBy("mLock")
+ private DeviceStateRequest mDeviceStateRequest;
+
+ public WindowAreaComponentImpl(@NonNull Context context) {
+ mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
+ mExecutor = context.getMainExecutor();
+
+ // TODO(b/236022708) Move rear display state to device state config file
+ mRearDisplayState = context.getResources().getInteger(
+ R.integer.config_deviceStateRearDisplay);
+
+ mDeviceStateManager.registerCallback(mExecutor, this);
+ }
+
+ /**
+ * Adds a listener interested in receiving updates on the RearDisplayStatus
+ * of the device. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer at the initial call site.
+ *
+ * Depending on the initial state of the device, we will return either
+ * {@link WindowAreaComponent#STATUS_AVAILABLE} or
+ * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that
+ * state respectively. When the rear display feature is triggered, we update the status to be
+ * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. TODO(b/240727590) Prefix with AREA_
+ *
+ * TODO(b/239833099) Add a STATUS_ACTIVE option to let apps know if a feature is currently
+ * enabled.
+ *
+ * @param consumer {@link Consumer} interested in receiving updates to the status of
+ * rear display mode.
+ */
+ public void addRearDisplayStatusListener(
+ @NonNull Consumer<@WindowAreaStatus Integer> consumer) {
+ synchronized (mLock) {
+ mRearDisplayStatusListeners.add(consumer);
+
+ // If current device state is still invalid, we haven't gotten our initial value yet
+ if (mCurrentDeviceState == INVALID_DEVICE_STATE) {
+ return;
+ }
+ consumer.accept(getCurrentStatus());
+ }
+ }
+
+ /**
+ * Removes a listener no longer interested in receiving updates.
+ * @param consumer no longer interested in receiving updates to RearDisplayStatus
+ */
+ public void removeRearDisplayStatusListener(
+ @NonNull Consumer<@WindowAreaStatus Integer> consumer) {
+ synchronized (mLock) {
+ mRearDisplayStatusListeners.remove(consumer);
+ }
+ }
+
+ /**
+ * Creates and starts a rear display session and provides updates to the
+ * callback provided. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer at the initial call site.
+ *
+ * When we enable rear display mode, we submit a request to {@link DeviceStateManager}
+ * to override the device state to the state that corresponds to RearDisplay
+ * mode. When the {@link DeviceStateRequest} is activated, we let the
+ * consumer know that the session is active by sending
+ * {@link WindowAreaComponent#SESSION_STATE_ACTIVE}.
+ *
+ * @param activity to provide updates to the client on
+ * the status of the Session
+ * @param rearDisplaySessionCallback to provide updates to the client on
+ * the status of the Session
+ */
+ public void startRearDisplaySession(@NonNull Activity activity,
+ @NonNull Consumer<@WindowAreaSessionState Integer> rearDisplaySessionCallback) {
+ synchronized (mLock) {
+ if (mDeviceStateRequest != null) {
+ // Rear display session is already active
+ throw new IllegalStateException(
+ "Unable to start new rear display session as one is already active");
+ }
+ mDeviceStateRequest = DeviceStateRequest.newBuilder(mRearDisplayState).build();
+ mDeviceStateManager.requestState(
+ mDeviceStateRequest,
+ mExecutor,
+ new DeviceStateRequestCallbackAdapter(rearDisplaySessionCallback)
+ );
+ }
+ }
+
+ /**
+ * Ends the current rear display session and provides updates to the
+ * callback provided. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer.
+ */
+ public void endRearDisplaySession() {
+ synchronized (mLock) {
+ if (mDeviceStateRequest != null || isRearDisplayActive()) {
+ mDeviceStateRequest = null;
+ mDeviceStateManager.cancelStateRequest();
+ } else {
+ throw new IllegalStateException(
+ "Unable to cancel a rear display session as there is no active session");
+ }
+ }
+ }
+
+ @Override
+ public void onBaseStateChanged(int state) {
+ synchronized (mLock) {
+ mCurrentDeviceBaseState = state;
+ if (state == mCurrentDeviceState) {
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+
+ @Override
+ public void onStateChanged(int state) {
+ synchronized (mLock) {
+ mCurrentDeviceState = state;
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+
+ @GuardedBy("mLock")
+ private int getCurrentStatus() {
+ if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE
+ || isRearDisplayActive()) {
+ return WindowAreaComponent.STATUS_UNAVAILABLE;
+ }
+ return WindowAreaComponent.STATUS_AVAILABLE;
+ }
+
+ /**
+ * Helper method to determine if a rear display session is currently active by checking
+ * if the current device configuration matches that of rear display. This would be true
+ * if there is a device override currently active (base state != current state) and the current
+ * state is that which corresponds to {@code mRearDisplayState}
+ * @return {@code true} if the device is in rear display mode and {@code false} if not
+ */
+ @GuardedBy("mLock")
+ private boolean isRearDisplayActive() {
+ return (mCurrentDeviceState != mCurrentDeviceBaseState) && (mCurrentDeviceState
+ == mRearDisplayState);
+ }
+
+ @GuardedBy("mLock")
+ private void updateStatusConsumers(@WindowAreaStatus int windowAreaStatus) {
+ synchronized (mLock) {
+ for (int i = 0; i < mRearDisplayStatusListeners.size(); i++) {
+ mRearDisplayStatusListeners.valueAt(i).accept(windowAreaStatus);
+ }
+ }
+ }
+
+ /**
+ * Callback for the {@link DeviceStateRequest} to be notified of when the request has been
+ * activated or cancelled. This callback provides information to the client library
+ * on the status of the RearDisplay session through {@code mRearDisplaySessionCallback}
+ */
+ private class DeviceStateRequestCallbackAdapter implements DeviceStateRequest.Callback {
+
+ private final Consumer<Integer> mRearDisplaySessionCallback;
+
+ DeviceStateRequestCallbackAdapter(@NonNull Consumer<Integer> callback) {
+ mRearDisplaySessionCallback = callback;
+ }
+
+ @Override
+ public void onRequestActivated(@NonNull DeviceStateRequest request) {
+ synchronized (mLock) {
+ if (request.equals(mDeviceStateRequest)) {
+ mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_ACTIVE;
+ mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus);
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+
+ @Override
+ public void onRequestCanceled(DeviceStateRequest request) {
+ synchronized (mLock) {
+ if (request.equals(mDeviceStateRequest)) {
+ mDeviceStateRequest = null;
+ }
+ mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE;
+ mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus);
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 918e514..e9a1721 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 85c8ebf..83ba909 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -80,7 +80,10 @@
public static final int PARALLAX_DISMISSING = 1;
public static final int PARALLAX_ALIGN_CENTER = 2;
- private static final int FLING_ANIMATION_DURATION = 250;
+ private static final int FLING_RESIZE_DURATION = 250;
+ private static final int FLING_SWITCH_DURATION = 350;
+ private static final int FLING_ENTER_DURATION = 350;
+ private static final int FLING_EXIT_DURATION = 350;
private final int mDividerWindowWidth;
private final int mDividerInsets;
@@ -93,6 +96,9 @@
private final Rect mBounds1 = new Rect();
// Bounds2 final position should be always at bottom or right
private final Rect mBounds2 = new Rect();
+ // The temp bounds outside of display bounds for side stage when split screen inactive to avoid
+ // flicker next time active split screen.
+ private final Rect mInvisibleBounds = new Rect();
private final Rect mWinBounds1 = new Rect();
private final Rect mWinBounds2 = new Rect();
private final SplitLayoutHandler mSplitLayoutHandler;
@@ -141,6 +147,10 @@
resetDividerPosition();
mDimNonImeSide = resources.getBoolean(R.bool.config_dimNonImeAttachedSide);
+
+ mInvisibleBounds.set(mRootBounds);
+ mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0,
+ isLandscape() ? 0 : mRootBounds.bottom);
}
private int getDividerInsets(Resources resources, Display display) {
@@ -239,6 +249,12 @@
rect.offset(-mRootBounds.left, -mRootBounds.top);
}
+ /** Gets bounds size equal to root bounds but outside of screen, used for position side stage
+ * when split inactive to avoid flicker when next time active. */
+ public void getInvisibleBounds(Rect rect) {
+ rect.set(mInvisibleBounds);
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -284,6 +300,10 @@
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
initDividerPosition(mTempRect);
+ mInvisibleBounds.set(mRootBounds);
+ mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0,
+ isLandscape() ? 0 : mRootBounds.bottom);
+
return true;
}
@@ -405,6 +425,13 @@
mFreezeDividerWindow = freezeDividerWindow;
}
+ /** Update current layout as divider put on start or end position. */
+ public void setDividerAtBorder(boolean start) {
+ final int pos = start ? mDividerSnapAlgorithm.getDismissStartTarget().position
+ : mDividerSnapAlgorithm.getDismissEndTarget().position;
+ setDividePosition(pos, false /* applyLayoutChange */);
+ }
+
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -449,17 +476,17 @@
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.flag) {
case FLAG_DISMISS_START:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
case FLAG_DISMISS_END:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
default:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> setDividePosition(snapTarget.position, true /* applyLayoutChange */));
break;
}
@@ -516,12 +543,20 @@
public void flingDividerToDismiss(boolean toEnd, int reason) {
final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position
: mDividerSnapAlgorithm.getDismissStartTarget().position;
- flingDividePosition(getDividePosition(), target,
+ flingDividePosition(getDividePosition(), target, FLING_EXIT_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason));
}
+ /** Fling divider from current position to center position. */
+ public void flingDividerToCenter() {
+ final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
+ flingDividePosition(getDividePosition(), pos, FLING_ENTER_DURATION,
+ () -> setDividePosition(pos, true /* applyLayoutChange */));
+ }
+
@VisibleForTesting
- void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
+ void flingDividePosition(int from, int to, int duration,
+ @Nullable Runnable flingFinishedCallback) {
if (from == to) {
// No animation run, still callback to stop resizing.
mSplitLayoutHandler.onLayoutSizeChanged(this);
@@ -531,7 +566,7 @@
}
ValueAnimator animator = ValueAnimator
.ofInt(from, to)
- .setDuration(FLING_ANIMATION_DURATION);
+ .setDuration(duration);
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addUpdateListener(
animation -> updateDivideBounds((int) animation.getAnimatedValue()));
@@ -588,7 +623,7 @@
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1, animator2, animator3);
- set.setDuration(FLING_ANIMATION_DURATION);
+ set.setDuration(FLING_SWITCH_DURATION);
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 7e83d2f..21fc01e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -25,6 +25,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -488,13 +489,6 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
- // If split still not active, apply windows bounds first to avoid surface reset to
- // wrong pos by SurfaceAnimator from wms.
- // TODO(b/223325631): check is it still necessary after improve enter transition done.
- if (!mMainStage.isActive()) {
- updateWindowBounds(mSplitLayout, wct);
- }
-
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
@@ -641,7 +635,7 @@
wct.startTask(sideTaskId, sideOptions);
}
// Using legacy transitions, so we can't use blast sync since it conflicts.
- mTaskOrganizer.applyTransaction(wct);
+ mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
setDividerVisibility(true, t);
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
@@ -893,10 +887,13 @@
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
+ mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null) {
mSideStage.removeAllTasks(wct, false /* toTop */);
mMainStage.deactivate(wct, false /* toTop */);
wct.reorder(mRootTaskInfo.token, false /* onTop */);
+ wct.setForceTranslucent(mRootTaskInfo.token, true);
+ wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
onTransitionAnimationComplete();
} else {
// Expand to top side split as full screen for fading out decor animation and dismiss
@@ -907,27 +904,32 @@
? mSideStage : mMainStage;
tempFullStage.resetBounds(wct);
wct.setSmallestScreenWidthDp(tempFullStage.mRootTaskInfo.token,
- mRootTaskInfo.configuration.smallestScreenWidthDp);
+ SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
dismissStage.dismiss(wct, false /* toTop */);
}
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
t.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null);
- t.setPosition(mMainStage.mRootLeash, 0, 0)
- .setPosition(mSideStage.mRootLeash, 0, 0);
t.hide(mMainStage.mDimLayer).hide(mSideStage.mDimLayer);
setDividerVisibility(false, t);
- // In this case, exit still under progress, fade out the split decor after first WCT
- // done and do remaining WCT after animation finished.
- if (childrenToTop != null) {
+ if (childrenToTop == null) {
+ t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+ } else {
+ // In this case, exit still under progress, fade out the split decor after first WCT
+ // done and do remaining WCT after animation finished.
childrenToTop.fadeOutDecor(() -> {
WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
mIsExiting = false;
childrenToTop.dismiss(finishedWCT, true /* toTop */);
finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
- mTaskOrganizer.applyTransaction(finishedWCT);
+ finishedWCT.setForceTranslucent(mRootTaskInfo.token, true);
+ finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ mSyncQueue.queue(finishedWCT);
+ mSyncQueue.runInSync(at -> {
+ at.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+ });
onTransitionAnimationComplete();
});
}
@@ -996,6 +998,7 @@
mMainStage.activate(wct, true /* includingTopTask */);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
}
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
@@ -1221,7 +1224,13 @@
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- mTaskOrganizer.applyTransaction(wct);
+ wct.setForceTranslucent(mRootTaskInfo.token, true);
+ mSplitLayout.getInvisibleBounds(mTempRect1);
+ wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
+ });
}
private void onRootTaskVanished() {
@@ -1377,10 +1386,17 @@
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status
final WindowContainerTransaction wct = new WindowContainerTransaction();
mSplitLayout.init();
- prepareEnterSplitScreen(wct);
+ mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+ mMainStage.activate(wct, true /* includingTopTask */);
+ updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t ->
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+
+ mSplitLayout.flingDividerToCenter();
+ });
}
if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true;
@@ -1822,6 +1838,7 @@
// properly for the animation itself.
mSplitLayout.release();
mSplitLayout.resetDividerPosition();
+ mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 95725bb..695550d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -159,7 +159,8 @@
}
private void waitDividerFlingFinished() {
- verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture());
+ verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(),
+ mRunnableCaptor.capture());
mRunnableCaptor.getValue().run();
}
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index a0bc5aa..2aeb42c 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -16,7 +16,8 @@
#include "TestSceneBase.h"
-#include <SkColorMatrixFilter.h>
+#include <SkColorFilter.h>
+#include <SkColorMatrix.h>
#include <SkGradientShader.h>
class SimpleColorMatrixAnimation;
diff --git a/media/Android.bp b/media/Android.bp
index d28a21c..ec243bf 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -113,7 +113,7 @@
min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
},
},
diff --git a/media/java/android/media/BluetoothProfileConnectionInfo.java b/media/java/android/media/BluetoothProfileConnectionInfo.java
index f3a65a1..a316c21 100644
--- a/media/java/android/media/BluetoothProfileConnectionInfo.java
+++ b/media/java/android/media/BluetoothProfileConnectionInfo.java
@@ -126,7 +126,6 @@
}
/**
- * @hide
* Factory method for <code>BluetoothProfileConnectionInfo</code> for an LE output device
* @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
* intent will not be sent.
diff --git a/media/java/android/media/tv/AdResponse.java b/media/java/android/media/tv/AdResponse.java
index 0c20954..08c66ab 100644
--- a/media/java/android/media/tv/AdResponse.java
+++ b/media/java/android/media/tv/AdResponse.java
@@ -25,7 +25,7 @@
import java.lang.annotation.RetentionPolicy;
/**
- * An advertisement request which can be sent to TV interactive App service to inform AD status.
+ * An advertisement response which can be sent to TV interactive App service to inform AD status.
*/
public final class AdResponse implements Parcelable {
/** @hide */
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index 9f92887..a72f34c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -217,7 +217,7 @@
case DO_DISPATCH_SURFACE_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
mSessionImpl.dispatchSurfaceChanged(
- (Integer) args.arg1, (Integer) args.arg2, (Integer) args.arg3);
+ (Integer) args.argi1, (Integer) args.argi2, (Integer) args.argi3);
args.recycle();
break;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
new file mode 100644
index 0000000..d40f322
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
@@ -0,0 +1,2 @@
+# Default reviewers for this and subdirectories.
+shaoweishen@google.com
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index bc9490f..5aae1ce 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -182,6 +182,7 @@
Settings.Secure.PEOPLE_STRIP,
Settings.Secure.MEDIA_CONTROLS_RESUME,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 2c99d71..67ea024 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -277,6 +277,7 @@
VALIDATORS.put(Secure.PEOPLE_STRIP, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MEDIA_CONTROLS_RESUME, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MEDIA_CONTROLS_RECOMMENDATION, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.MEDIA_CONTROLS_LOCK_SCREEN, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
new InclusiveIntegerRangeValidator(
Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index fd7554f..528af2e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -376,9 +376,11 @@
Setting newSetting = new Setting(name, oldSetting.getValue(), null,
oldSetting.getPackageName(), oldSetting.getTag(), false,
oldSetting.getId());
- mSettings.put(name, newSetting);
- updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,
+ int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,
newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+ checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
+ mSettings.put(name, newSetting);
+ updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
scheduleWriteIfNeededLocked();
}
}
@@ -410,6 +412,12 @@
Setting oldState = mSettings.get(name);
String oldValue = (oldState != null) ? oldState.value : null;
String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
+ String newDefaultValue = makeDefault ? value : oldDefaultValue;
+
+ int newSize = getNewMemoryUsagePerPackageLocked(packageName, oldValue, value,
+ oldDefaultValue, newDefaultValue);
+ checkNewMemoryUsagePerPackageLocked(packageName, newSize);
+
Setting newState;
if (oldState != null) {
@@ -430,8 +438,7 @@
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
- updateMemoryUsagePerPackageLocked(packageName, oldValue, value,
- oldDefaultValue, newState.getDefaultValue());
+ updateMemoryUsagePerPackageLocked(packageName, newSize);
scheduleWriteIfNeededLocked();
@@ -552,13 +559,14 @@
}
Setting oldState = mSettings.remove(name);
+ int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
+ null, oldState.defaultValue, null);
FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "",
/* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
- updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
- null, oldState.defaultValue, null);
+ updateMemoryUsagePerPackageLocked(oldState.packageName, newSize);
addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
@@ -579,16 +587,18 @@
Setting oldSetting = new Setting(setting);
String oldValue = setting.getValue();
String oldDefaultValue = setting.getDefaultValue();
+ String newValue = oldDefaultValue;
+ String newDefaultValue = oldDefaultValue;
+
+ int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, oldValue,
+ newValue, oldDefaultValue, newDefaultValue);
+ checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize);
if (!setting.reset()) {
return false;
}
- String newValue = setting.getValue();
- String newDefaultValue = setting.getDefaultValue();
-
- updateMemoryUsagePerPackageLocked(setting.packageName, oldValue,
- newValue, oldDefaultValue, newDefaultValue);
+ updateMemoryUsagePerPackageLocked(setting.packageName, newSize);
addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting);
@@ -696,38 +706,49 @@
}
@GuardedBy("mLock")
- private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
+ private boolean isExemptFromMemoryUsageCap(String packageName) {
+ return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED
+ || SYSTEM_PACKAGE_NAME.equals(packageName);
+ }
+
+ @GuardedBy("mLock")
+ private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize)
+ throws IllegalStateException {
+ if (isExemptFromMemoryUsageCap(packageName)) {
+ return;
+ }
+ if (newSize > mMaxBytesPerAppPackage) {
+ throw new IllegalStateException("You are adding too many system settings. "
+ + "You should stop using system settings for app specific data"
+ + " package: " + packageName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private int getNewMemoryUsagePerPackageLocked(String packageName, String oldValue,
String newValue, String oldDefaultValue, String newDefaultValue) {
- if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
- return;
+ if (isExemptFromMemoryUsageCap(packageName)) {
+ return 0;
}
-
- if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
- return;
- }
-
+ final Integer currentSize = mPackageToMemoryUsage.get(packageName);
final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
final int newValueSize = (newValue != null) ? newValue.length() : 0;
final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
final int deltaSize = newValueSize + newDefaultValueSize
- oldValueSize - oldDefaultValueSize;
+ return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0);
+ }
- Integer currentSize = mPackageToMemoryUsage.get(packageName);
- final int newSize = Math.max((currentSize != null)
- ? currentSize + deltaSize : deltaSize, 0);
-
- if (newSize > mMaxBytesPerAppPackage) {
- throw new IllegalStateException("You are adding too many system settings. "
- + "You should stop using system settings for app specific data"
- + " package: " + packageName);
+ @GuardedBy("mLock")
+ private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) {
+ if (isExemptFromMemoryUsageCap(packageName)) {
+ return;
}
-
if (DEBUG) {
Slog.i(LOG_TAG, "Settings for package: " + packageName
+ " size: " + newSize + " bytes.");
}
-
mPackageToMemoryUsage.put(packageName, newSize);
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 69eb713..a637efa 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -20,6 +20,8 @@
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.google.common.base.Strings;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -276,4 +278,39 @@
settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
return settingsState;
}
+
+ public void testInsertSetting_memoryUsage() {
+ SettingsState settingsState = getSettingStateObject();
+ // No exception should be thrown when there is no cap
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ settingsState.deleteSettingLocked(SETTING_NAME);
+
+ settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
+ SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+ // System package doesn't have memory usage limit
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, SYSTEM_PACKAGE);
+ settingsState.deleteSettingLocked(SETTING_NAME);
+
+ // Should not throw if usage is under the cap
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19999),
+ null, false, "p1");
+ settingsState.deleteSettingLocked(SETTING_NAME);
+ try {
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("p1"));
+ }
+ try {
+ settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
+ null, false, "p1");
+ fail("Should throw because it exceeded per package memory usage");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("p1"));
+ }
+ assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull());
+ }
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6edf13a..652e281 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -394,6 +394,11 @@
android:label="@string/screenshot_scroll_label"
android:finishOnTaskLaunch="true" />
+ <service android:name=".screenshot.ScreenshotProxyService"
+ android:permission="com.android.systemui.permission.SELF"
+ android:exported="false" />
+
+
<service android:name=".screenrecord.RecordingService" />
<receiver android:name=".SysuiRestartReceiver"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 61fac29..4a6164c 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -14,11 +14,10 @@
brycelee@google.com
ccassidy@google.com
chrisgollner@google.com
-cinek@google.com
-cwren@google.com
dupin@google.com
ethibodeau@google.com
evanlaird@google.com
+florenceyang@google.com
gwasserman@google.com
hwwang@google.com
hyunyoungs@google.com
@@ -27,36 +26,36 @@
jbolinger@google.com
jdemeulenaere@google.com
jeffdq@google.com
+jernej@google.com
+jglazier@google.com
jjaggi@google.com
jonmiranda@google.com
joshtrask@google.com
juliacr@google.com
juliatuttle@google.com
justinkoh@google.com
-kchyn@google.com
kozynski@google.com
kprevas@google.com
lynhan@google.com
madym@google.com
mankoff@google.com
-mett@google.com
mkephart@google.com
mpietal@google.com
mrcasey@google.com
mrenouf@google.com
-nesciosquid@google.com
nickchameyev@google.com
nicomazz@google.com
ogunwale@google.com
peanutbutter@google.com
+peskal@google.com
pinyaoting@google.com
pixel@google.com
+pomini@google.com
rahulbanerjee@google.com
roosa@google.com
santie@google.com
shanh@google.com
snoeberger@google.com
-sreyasr@google.com
steell@google.com
sfufa@google.com
stwu@google.com
@@ -70,15 +69,10 @@
victortulias@google.com
winsonc@google.com
wleshner@google.com
-yurilin@google.com
xuqiu@google.com
+yuandizhou@google.com
+yurilin@google.com
zakcohen@google.com
-jernej@google.com
-jglazier@google.com
-peskal@google.com
-
-#Android Auto
-hseog@google.com
#Android TV
rgl@google.com
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 1008481..1ac1e3a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -17,6 +17,7 @@
import android.graphics.drawable.Drawable
import android.view.View
import com.android.systemui.plugins.annotations.ProvidesInterface
+import com.android.systemui.shared.regionsampling.RegionDarkness
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
@@ -116,12 +117,3 @@
val clockId: ClockId,
val name: String
)
-
-/**
- * Enum for whether clock region is dark or light.
- */
-enum class RegionDarkness(val isDark: Boolean) {
- DEFAULT(false),
- DARK(true),
- LIGHT(false)
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt b/packages/SystemUI/plugin/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
new file mode 100644
index 0000000..344fdb8
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
@@ -0,0 +1,10 @@
+package com.android.systemui.shared.regionsampling
+
+/**
+ * Enum for whether clock region is dark or light.
+ */
+enum class RegionDarkness(val isDark: Boolean) {
+ DEFAULT(false),
+ DARK(true),
+ LIGHT(false)
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 8f1959e..a21a78b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -50,7 +50,12 @@
defStyleRes: Int = 0
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
- private var lastMeasureCall: CharSequence = ""
+ private var lastMeasureCall: CharSequence? = null
+ private var lastDraw: CharSequence? = null
+ private var lastTextUpdate: CharSequence? = null
+ private var lastOnTextChanged: CharSequence? = null
+ private var lastInvalidate: CharSequence? = null
+ private var lastTimeZoneChange: CharSequence? = null
private val time = Calendar.getInstance()
@@ -142,7 +147,6 @@
// relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) {
text = formattedText
-
// Because the TextLayout may mutate under the hood as a result of the new text, we
// notify the TextAnimator that it may have changed and request a measure/layout. A
// crash will occur on the next invocation of setTextStyle if the layout is mutated
@@ -151,18 +155,19 @@
textAnimator?.updateLayout(layout)
}
requestLayout()
+ lastTextUpdate = getTimestamp()
}
}
fun onTimeZoneChanged(timeZone: TimeZone?) {
time.timeZone = timeZone
refreshFormat()
+ lastTimeZoneChange = "${getTimestamp()} timeZone=${time.timeZone}"
}
@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- lastMeasureCall = DateFormat.format(descFormat, System.currentTimeMillis())
val animator = textAnimator
if (animator == null) {
textAnimator = TextAnimator(layout) { invalidate() }
@@ -171,13 +176,34 @@
} else {
animator.updateLayout(layout)
}
+ lastMeasureCall = getTimestamp()
}
override fun onDraw(canvas: Canvas) {
+ lastDraw = getTimestamp()
// intentionally doesn't call super.onDraw here or else the text will be rendered twice
textAnimator?.draw(canvas)
}
+ override fun invalidate() {
+ super.invalidate()
+ lastInvalidate = getTimestamp()
+ }
+
+ private fun getTimestamp(): CharSequence {
+ return "${DateFormat.format("HH:mm:ss", System.currentTimeMillis())} text=$text"
+ }
+
+ override fun onTextChanged(
+ text: CharSequence,
+ start: Int,
+ lengthBefore: Int,
+ lengthAfter: Int
+ ) {
+ super.onTextChanged(text, start, lengthBefore, lengthAfter)
+ lastOnTextChanged = "${getTimestamp()}"
+ }
+
fun setLineSpacingScale(scale: Float) {
lineSpacingScale = scale
setLineSpacing(0f, lineSpacingScale)
@@ -370,7 +396,12 @@
pw.println(" measuredWidth=$measuredWidth")
pw.println(" measuredHeight=$measuredHeight")
pw.println(" singleLineInternal=$isSingleLineInternal")
+ pw.println(" lastTextUpdate=$lastTextUpdate")
+ pw.println(" lastOnTextChanged=$lastOnTextChanged")
+ pw.println(" lastInvalidate=$lastInvalidate")
pw.println(" lastMeasureCall=$lastMeasureCall")
+ pw.println(" lastDraw=$lastDraw")
+ pw.println(" lastTimeZoneChange=$lastTimeZoneChange")
pw.println(" currText=$text")
pw.println(" currTimeContextDesc=$contentDescription")
pw.println(" time=$time")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 3d72f15..6c49186 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -26,8 +26,8 @@
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProvider
-import com.android.systemui.plugins.RegionDarkness
import com.android.systemui.shared.R
+import com.android.systemui.shared.regionsampling.RegionDarkness
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
index deabc27..0146795 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
@@ -18,7 +18,6 @@
import android.graphics.Rect
import android.view.View
import androidx.annotation.VisibleForTesting
-import com.android.systemui.plugins.RegionDarkness
import com.android.systemui.shared.navigationbar.RegionSamplingHelper
import com.android.systemui.shared.navigationbar.RegionSamplingHelper.SamplingCallback
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 49e378e..d96476f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -99,12 +99,11 @@
mProgressColor = context.getColor(R.color.udfps_enroll_progress);
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
+ mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
if (!mIsAccessibilityEnabled) {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
- mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
} else {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback);
- mOnFirstBucketFailedColor = mHelpColor;
}
mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
mCheckmarkDrawable.mutate();
@@ -167,7 +166,8 @@
}
private void updateProgress(int remainingSteps, int totalSteps, boolean showingHelp) {
- if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
+ if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps
+ && mShowingHelp == showingHelp) {
return;
}
@@ -197,6 +197,7 @@
}
}
+ mShowingHelp = showingHelp;
mRemainingSteps = remainingSteps;
mTotalSteps = totalSteps;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 5dff4a5..4157728 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -26,6 +26,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
@@ -61,6 +62,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -191,7 +193,9 @@
GroupMembershipManager groupManager,
VisualStabilityProvider visualStabilityProvider,
ConfigurationController configurationController,
- @Main Handler handler) {
+ @Main Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
return new HeadsUpManagerPhone(
context,
headsUpManagerLogger,
@@ -200,7 +204,9 @@
groupManager,
visualStabilityProvider,
configurationController,
- handler
+ handler,
+ accessibilityManagerWrapper,
+ uiEventLogger
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f32ea35..2dadf57 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,6 +18,7 @@
import android.app.INotificationManager;
import android.content.Context;
+import android.service.dreams.IDreamManager;
import androidx.annotation.Nullable;
@@ -213,6 +214,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -230,6 +232,7 @@
shadeController,
statusBarService,
notificationManager,
+ dreamManager,
visibilityProvider,
interruptionStateProvider,
zenModeController,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 42e6b02..1f356cb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -182,6 +182,7 @@
public static final UnreleasedFlag MEDIA_SESSION_ACTIONS = new UnreleasedFlag(901);
public static final ReleasedFlag MEDIA_NEARBY_DEVICES = new ReleasedFlag(903);
public static final ReleasedFlag MEDIA_MUTE_AWAIT = new ReleasedFlag(904);
+ public static final UnreleasedFlag MEDIA_DREAM_COMPLICATION = new UnreleasedFlag(905);
// 1000 - dock
public static final ReleasedFlag SIMULATE_DOCK_THROUGH_CHARGING =
@@ -236,6 +237,7 @@
// 1300 - screenshots
public static final UnreleasedFlag SCREENSHOT_REQUEST_PROCESSOR = new UnreleasedFlag(1300);
+ public static final UnreleasedFlag SCREENSHOT_WORK_PROFILE_POLICY = new UnreleasedFlag(1301);
// 1400 - columbus, b/242800729
public static final UnreleasedFlag QUICK_TAP_IN_PCC = new UnreleasedFlag(1400);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index ca65d12..da5819a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -90,6 +90,8 @@
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
import android.widget.TextView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -155,6 +157,8 @@
public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
+ private static final boolean DEBUG = false;
+
private static final String TAG = "GlobalActionsDialogLite";
private static final String INTERACTION_JANK_TAG = "global_actions";
@@ -2177,6 +2181,11 @@
protected ViewGroup mContainer;
+ private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+ logOnBackInvocation();
+ dismiss();
+ };
+
@VisibleForTesting
protected GestureDetector.SimpleOnGestureListener mGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@@ -2221,6 +2230,16 @@
}
};
+
+ // this exists so that we can point it to a mock during Unit Testing
+ private OnBackInvokedDispatcher mOverriddenBackDispatcher;
+
+ // the following method exists so that a Unit Test can supply a `OnBackInvokedDispatcher`
+ @VisibleForTesting
+ void setBackDispatcherOverride(OnBackInvokedDispatcher mockDispatcher) {
+ mOverriddenBackDispatcher = mockDispatcher;
+ }
+
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
@@ -2254,6 +2273,22 @@
super.onCreate(savedInstanceState);
initializeLayout();
mWindowDimAmount = getWindow().getAttributes().dimAmount;
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
+ if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler registered");
+ }
+
+ @VisibleForTesting
+ @Override
+ public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+ if (mOverriddenBackDispatcher != null) return mOverriddenBackDispatcher;
+ else return super.getOnBackInvokedDispatcher();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+ if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler unregistered");
}
@Override
@@ -2453,7 +2488,12 @@
@Override
public void onBackPressed() {
super.onBackPressed();
+ logOnBackInvocation();
+ }
+
+ private void logOnBackInvocation() {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_BACK);
+ if (DEBUG) Log.d(TAG, "onBack invoked");
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 3eb3c80..6dfbd42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -323,6 +323,8 @@
if (sEnableRemoteKeyguardOccludeAnimation) {
Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
// Register for occluding
+ final RemoteTransition occludeTransition = new RemoteTransition(
+ mOccludeAnimation, getIApplicationThread());
TransitionFilter f = new TransitionFilter();
f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
f.mRequirements = new TransitionFilter.Requirement[]{
@@ -337,10 +339,11 @@
f.mRequirements[1].mMustBeIndependent = false;
f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- mShellTransitions.registerRemote(f,
- new RemoteTransition(mOccludeAnimation, getIApplicationThread()));
+ mShellTransitions.registerRemote(f, occludeTransition);
// Now register for un-occlude.
+ final RemoteTransition unoccludeTransition = new RemoteTransition(
+ mUnoccludeAnimation, getIApplicationThread());
f = new TransitionFilter();
f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
f.mRequirements = new TransitionFilter.Requirement[]{
@@ -358,8 +361,23 @@
f.mRequirements[0].mMustBeIndependent = false;
f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- mShellTransitions.registerRemote(f,
- new RemoteTransition(mUnoccludeAnimation, getIApplicationThread()));
+ mShellTransitions.registerRemote(f, unoccludeTransition);
+
+ // Register for specific transition type.
+ // Above filter cannot fulfill all conditions.
+ // E.g. close top activity while screen off but next activity is occluded, this should
+ // an occluded transition, but since the activity is invisible, the condition would
+ // match unoccluded transition.
+ // But on the contrary, if we add above condition in occluded transition, then when user
+ // trying to dismiss occluded activity when unlock keyguard, the condition would match
+ // occluded transition.
+ f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE};
+ mShellTransitions.registerRemote(f, occludeTransition);
+
+ f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE};
+ mShellTransitions.registerRemote(f, unoccludeTransition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b4f40e2..4a7346e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2377,10 +2377,10 @@
private void handleHide() {
Trace.beginSection("KeyguardViewMediator#handleHide");
- // It's possible that the device was unlocked in a dream state. It's time to wake up.
- if (mAodShowing || mDreamOverlayShowing) {
- PowerManager pm = mContext.getSystemService(PowerManager.class);
- pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ // It's possible that the device was unlocked (via BOUNCER) while dozing. It's time to
+ // wake up.
+ if (mAodShowing) {
+ mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:BOUNCER_DOZING");
}
@@ -2409,6 +2409,13 @@
null /* nonApps */, null /* finishedCallback */);
});
}
+
+ // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
+ // dreaming. It's time to wake up.
+ if (mDreamOverlayShowing) {
+ mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:UNLOCK_DREAMING");
+ }
}
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 237b505..32600fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -18,19 +18,25 @@
import android.content.Context
import android.content.res.Configuration
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.LargeScreenUtils
+import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import javax.inject.Named
@@ -43,9 +49,10 @@
@param:Named(KEYGUARD) private val mediaHost: MediaHost,
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
- private val notifLockscreenUserManager: NotificationLockscreenUserManager,
private val context: Context,
- configurationController: ConfigurationController
+ private val secureSettings: SecureSettings,
+ @Main private val handler: Handler,
+ configurationController: ConfigurationController,
) {
init {
@@ -60,6 +67,24 @@
}
})
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
+ refreshMediaPosition()
+ }
+ }
+ }
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
// First let's set the desired state that we want for this host
mediaHost.expansion = MediaHostState.EXPANDED
mediaHost.showsOnlyActiveMedia = true
@@ -101,6 +126,13 @@
private var splitShadeContainer: ViewGroup? = null
/**
+ * Track the media player setting status on lock screen.
+ */
+ private var allowMediaPlayerOnLockScreen: Boolean = true
+ private val lockScreenMediaPlayerUri =
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+
+ /**
* Attaches media container in single pane mode, situated at the top of the notifications list
*/
fun attachSinglePaneContainer(mediaView: MediaContainerView?) {
@@ -164,7 +196,7 @@
visible = mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
- notifLockscreenUserManager.shouldShowLockscreenNotifications()
+ allowMediaPlayerOnLockScreen
if (visible) {
showMediaPlayer()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 88a1b17..7b497ad 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
+import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
@@ -27,6 +28,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.ImageDecoder
@@ -57,8 +59,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
+import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Assert
@@ -633,9 +635,14 @@
}
val mediaController = mediaControllerFactory.create(token)
val metadata = mediaController.metadata
+ val notif: Notification = sbn.notification
+
+ val appInfo = notif.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ ) ?: getAppInfoFromPackage(sbn.packageName)
// Album art
- val notif: Notification = sbn.notification
var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
if (artworkBitmap == null) {
artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
@@ -650,8 +657,7 @@
}
// App name
- val builder = Notification.Builder.recoverBuilder(context, notif)
- val app = builder.loadHeaderAppName()
+ val appName = getAppName(sbn, appInfo)
// App Icon
val smallIcon = sbn.notification.smallIcon
@@ -712,12 +718,7 @@
val currentEntry = mediaEntries.get(key)
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
- val appUid = try {
- context.packageManager.getApplicationInfo(sbn.packageName, 0)?.uid!!
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Could not get app UID for ${sbn.packageName}", e)
- Process.INVALID_UID
- }
+ val appUid = appInfo?.uid ?: Process.INVALID_UID
if (logEvent) {
logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
@@ -730,7 +731,7 @@
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
val active = mediaEntries[key]?.active ?: true
- onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, app,
+ onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, appName,
smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
semanticActions, sbn.packageName, token, notif.contentIntent, device,
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
@@ -740,6 +741,28 @@
}
}
+ private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
+ try {
+ return context.packageManager.getApplicationInfo(packageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app info for $packageName", e)
+ }
+ return null
+ }
+
+ private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
+ val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
+ if (name != null) {
+ return name
+ }
+
+ return if (appInfo != null) {
+ context.packageManager.getApplicationLabel(appInfo).toString()
+ } else {
+ sbn.packageName
+ }
+ }
+
/**
* Generate action buttons based on notification actions
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 9260020..ae4c7c7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -22,7 +22,12 @@
import android.annotation.IntDef
import android.content.Context
import android.content.res.Configuration
+import android.database.ContentObserver
import android.graphics.Rect
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
import android.util.Log
import android.util.MathUtils
import android.view.View
@@ -33,12 +38,12 @@
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.NotifPanelEvents
import com.android.systemui.statusbar.CrossFadeHelper
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
@@ -47,6 +52,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.LargeScreenUtils
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.traceSection
import javax.inject.Inject
@@ -85,15 +91,23 @@
private val keyguardStateController: KeyguardStateController,
private val bypassController: KeyguardBypassController,
private val mediaCarouselController: MediaCarouselController,
- private val notifLockscreenUserManager: NotificationLockscreenUserManager,
private val keyguardViewController: KeyguardViewController,
private val dreamOverlayStateController: DreamOverlayStateController,
configurationController: ConfigurationController,
wakefulnessLifecycle: WakefulnessLifecycle,
panelEventsEvents: NotifPanelEvents,
+ private val secureSettings: SecureSettings,
+ @Main private val handler: Handler,
) {
/**
+ * Track the media player setting status on lock screen.
+ */
+ private var allowMediaPlayerOnLockScreen: Boolean = true
+ private val lockScreenMediaPlayerUri =
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+
+ /**
* Whether we "skip" QQS during panel expansion.
*
* This means that when expanding the panel we go directly to QS. Also when we are on QS and
@@ -521,6 +535,23 @@
updateDesiredLocation()
}
})
+
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
+ }
+ }
+ }
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL)
}
private fun updateConfiguration() {
@@ -1036,7 +1067,6 @@
}
val onLockscreen = (!bypassController.bypassEnabled &&
(statusbarState == StatusBarState.KEYGUARD))
- val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
val location = when {
dreamOverlayActive -> LOCATION_DREAM_OVERLAY
(qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
@@ -1044,7 +1074,7 @@
!hasActiveMedia -> LOCATION_QS
onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
- onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
+ onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
}
// When we're on lock screen and the player is not active, we should keep it in QS.
@@ -1116,7 +1146,7 @@
return !statusBarStateController.isDozing &&
!keyguardViewController.isBouncerShowing &&
statusBarStateController.state == StatusBarState.KEYGUARD &&
- notifLockscreenUserManager.shouldShowLockscreenNotifications() &&
+ allowMediaPlayerOnLockScreen &&
statusBarStateController.isExpanded &&
!qsExpanded
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index e077fed..c544871 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -16,6 +16,8 @@
package com.android.systemui.media.dream;
+import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+
import android.content.Context;
import androidx.annotation.NonNull;
@@ -23,6 +25,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.SmartspaceMediaData;
@@ -34,7 +37,7 @@
* the media complication as appropriate
*/
public class MediaDreamSentinel extends CoreStartable {
- private MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
+ private final MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
private boolean mAdded;
@Override
public void onSmartspaceMediaDataRemoved(@NonNull String key, boolean immediately) {
@@ -63,6 +66,10 @@
public void onMediaDataLoaded(@NonNull String key, @Nullable String oldKey,
@NonNull MediaData data, boolean immediately, int receivedSmartspaceCardLatency,
boolean isSsReactivated) {
+ if (!mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)) {
+ return;
+ }
+
if (mAdded) {
return;
}
@@ -79,15 +86,18 @@
private final MediaDataManager mMediaDataManager;
private final DreamOverlayStateController mDreamOverlayStateController;
private final MediaDreamComplication mComplication;
+ private final FeatureFlags mFeatureFlags;
@Inject
public MediaDreamSentinel(Context context, MediaDataManager mediaDataManager,
DreamOverlayStateController dreamOverlayStateController,
- MediaDreamComplication complication) {
+ MediaDreamComplication complication,
+ FeatureFlags featureFlags) {
super(context);
mMediaDataManager = mediaDataManager;
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = complication;
+ mFeatureFlags = featureFlags;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
new file mode 100644
index 0000000..f7c4dad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+/** Interface implemented by ScreenshotProxyService */
+interface IScreenshotProxy {
+
+ /** Is the notification shade currently exanded? */
+ boolean isNotificationShadeExpanded();
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
index 39f35a5..7779760 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
@@ -22,5 +22,5 @@
fun captureDisplay(displayId: Int, crop: Rect? = null): Bitmap?
- fun captureTask(taskId: Int): Bitmap?
+ suspend fun captureTask(taskId: Int): Bitmap?
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 258c436..246265b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -27,13 +27,19 @@
import android.view.SurfaceControl.DisplayCaptureArgs
import android.view.SurfaceControl.ScreenshotHardwareBuffer
import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
private const val TAG = "ImageCaptureImpl"
+@SysUISingleton
open class ImageCaptureImpl @Inject constructor(
private val displayManager: DisplayManager,
- private val atmService: IActivityTaskManager
+ private val atmService: IActivityTaskManager,
+ @Background private val bgContext: CoroutineDispatcher
) : ImageCapture {
override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {
@@ -46,8 +52,8 @@
return buffer?.asBitmap()
}
- override fun captureTask(taskId: Int): Bitmap? {
- val snapshot = atmService.takeTaskSnapshot(taskId)
+ override suspend fun captureTask(taskId: Int): Bitmap? {
+ val snapshot = withContext(bgContext) { atmService.takeTaskSnapshot(taskId) } ?: return null
return Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
}
@@ -67,12 +73,17 @@
}
@VisibleForTesting
- open fun captureDisplay(displayToken: IBinder, width: Int, height: Int, crop: Rect): ScreenshotHardwareBuffer? {
- val captureArgs = DisplayCaptureArgs.Builder(displayToken)
- .setSize(width, height)
- .setSourceCrop(crop)
- .build()
+ open fun captureDisplay(
+ displayToken: IBinder,
+ width: Int,
+ height: Int,
+ crop: Rect
+ ): ScreenshotHardwareBuffer? {
+ val captureArgs =
+ DisplayCaptureArgs.Builder(displayToken)
+ .setSize(width, height)
+ .setSourceCrop(crop)
+ .build()
return SurfaceControl.captureDisplay(captureArgs)
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index 4397d3d..a918e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -16,51 +16,84 @@
package com.android.systemui.screenshot
-import android.net.Uri
-import android.util.Log
-import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import android.graphics.Insets
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
import java.util.function.Consumer
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
/**
* Processes a screenshot request sent from {@link ScreenshotHelper}.
*/
@SysUISingleton
-internal class RequestProcessor @Inject constructor(
- private val controller: ScreenshotController,
+class RequestProcessor @Inject constructor(
+ private val capture: ImageCapture,
+ private val policy: ScreenshotPolicy,
+ private val flags: FeatureFlags,
+ /** For the Java Async version, to invoke the callback. */
+ @Application private val mainScope: CoroutineScope
) {
- fun processRequest(
- request: ScreenshotRequest,
- onSavedListener: Consumer<Uri>,
- callback: RequestCallback
- ) {
+ /**
+ * Inspects the incoming request, returning a potentially modified request depending on policy.
+ *
+ * @param request the request to process
+ */
+ suspend fun process(request: ScreenshotRequest): ScreenshotRequest {
+ var result = request
- if (request.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- val image = HardwareBitmapBundler.bundleToHardwareBitmap(request.bitmapBundle)
+ // Apply work profile screenshots policy:
+ //
+ // If the focused app belongs to a work profile, transforms a full screen
+ // (or partial) screenshot request to a task snapshot (provided image) screenshot.
- controller.handleImageAsScreenshot(
- image, request.boundsInScreen, request.insets,
- request.taskId, request.userId, request.topComponent, onSavedListener, callback
- )
- return
+ // Whenever displayContentInfo is fetched, the topComponent is also populated
+ // regardless of the managed profile status.
+
+ if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
+ flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+ ) {
+
+ val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
+
+ result = if (policy.isManagedProfile(info.userId)) {
+ val image = capture.captureTask(info.taskId)
+ ?: error("Task snapshot returned a null Bitmap!")
+
+ // Provide the task snapshot as the screenshot
+ ScreenshotRequest(
+ TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
+ HardwareBitmapBundler.hardwareBitmapToBundle(image),
+ info.bounds, Insets.NONE, info.taskId, info.userId, info.component
+ )
+ } else {
+ // Create a new request of the same type which includes the top component
+ ScreenshotRequest(request.source, request.type, info.component)
+ }
}
- when (request.type) {
- TAKE_SCREENSHOT_FULLSCREEN ->
- controller.takeScreenshotFullscreen(null, onSavedListener, callback)
- TAKE_SCREENSHOT_SELECTED_REGION ->
- controller.takeScreenshotPartial(null, onSavedListener, callback)
- else -> Log.w(TAG, "Invalid screenshot option: ${request.type}")
- }
+ return result
}
- companion object {
- const val TAG: String = "RequestProcessor"
+ /**
+ * Note: This is for compatibility with existing Java. Prefer the suspending function when
+ * calling from a Coroutine context.
+ *
+ * @param request the request to process
+ * @param callback the callback to provide the processed request, invoked from the main thread
+ */
+ fun processAsync(request: ScreenshotRequest, callback: Consumer<ScreenshotRequest>) {
+ mainScope.launch {
+ val result = process(request)
+ callback.accept(result)
+ }
}
}
+
+private const val TAG = "RequestProcessor"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
new file mode 100644
index 0000000..3580010
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.annotation.UserIdInt
+import android.content.ComponentName
+import android.graphics.Rect
+import android.view.Display
+
+/**
+ * Provides policy decision-making information to screenshot request handling.
+ */
+interface ScreenshotPolicy {
+
+ /** @return true if the user is a managed profile (a.k.a. work profile) */
+ suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean
+
+ /**
+ * Requests information about the owner of display content which occupies a majority of the
+ * screenshot and/or has most recently been interacted with at the time the screenshot was
+ * requested.
+ *
+ * @param displayId the id of the display to inspect
+ * @return content info for the primary content on the display
+ */
+ suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo
+
+ data class DisplayContentInfo(
+ val component: ComponentName,
+ val bounds: Rect,
+ @UserIdInt val userId: Int,
+ val taskId: Int,
+ )
+
+ fun getDefaultDisplayId(): Int = Display.DEFAULT_DISPLAY
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
new file mode 100644
index 0000000..ba809f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.annotation.UserIdInt
+import android.app.ActivityTaskManager
+import android.app.ActivityTaskManager.RootTaskInfo
+import android.app.IActivityTaskManager
+import android.app.WindowConfiguration
+import android.app.WindowConfiguration.activityTypeToString
+import android.app.WindowConfiguration.windowingModeToString
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Process
+import android.os.RemoteException
+import android.os.UserManager
+import android.util.Log
+import android.view.Display.DEFAULT_DISPLAY
+import com.android.internal.infra.ServiceConnector
+import com.android.systemui.SystemUIService
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+import java.util.Arrays
+import javax.inject.Inject
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+internal class ScreenshotPolicyImpl @Inject constructor(
+ context: Context,
+ private val userMgr: UserManager,
+ private val atmService: IActivityTaskManager,
+ @Background val bgDispatcher: CoroutineDispatcher,
+) : ScreenshotPolicy {
+
+ private val systemUiContent =
+ DisplayContentInfo(
+ ComponentName(context, SystemUIService::class.java),
+ Rect(),
+ ActivityTaskManager.INVALID_TASK_ID,
+ Process.myUserHandle().identifier,
+ )
+
+ private val proxyConnector: ServiceConnector<IScreenshotProxy> =
+ ServiceConnector.Impl(
+ context,
+ Intent(context, ScreenshotProxyService::class.java),
+ Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+ context.userId,
+ IScreenshotProxy.Stub::asInterface
+ )
+
+ override fun getDefaultDisplayId(): Int {
+ return DEFAULT_DISPLAY
+ }
+
+ override suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean {
+ return withContext(bgDispatcher) { userMgr.isManagedProfile(userId) }
+ }
+
+ private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
+ return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
+ info.isVisible &&
+ info.isRunning &&
+ info.numActivities > 0 &&
+ info.topActivity != null &&
+ info.childTaskIds.isNotEmpty()
+ }
+
+ /**
+ * Uses RootTaskInfo from ActivityTaskManager to guess at the primary focused task within a
+ * display. If no task is visible or the top task is covered by a system window, the info
+ * reported will reference a SystemUI component instead.
+ */
+ override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
+ // Determine if the notification shade is expanded. If so, task windows are not
+ // visible behind it, so the screenshot should instead be associated with SystemUI.
+ if (isNotificationShadeExpanded()) {
+ return systemUiContent
+ }
+
+ val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
+ if (DEBUG) {
+ debugLogRootTaskInfos(taskInfoList)
+ }
+
+ // If no visible task is located, then report SystemUI as the foreground content
+ val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent
+
+ val topActivity: ComponentName = target.topActivity ?: error("should not be null")
+ val topChildTask = target.childTaskIds.size - 1
+ val childTaskId = target.childTaskIds[topChildTask]
+ val childTaskUserId = target.childTaskUserIds[topChildTask]
+ val childTaskBounds = target.childTaskBounds[topChildTask]
+
+ return DisplayContentInfo(topActivity, childTaskBounds, childTaskId, childTaskUserId)
+ }
+
+ private fun debugLogRootTaskInfos(taskInfoList: List<RootTaskInfo>) {
+ for (info in taskInfoList) {
+ Log.d(
+ TAG,
+ "[root task info] " +
+ "taskId=${info.taskId} " +
+ "parentTaskId=${info.parentTaskId} " +
+ "position=${info.position} " +
+ "positionInParent=${info.positionInParent} " +
+ "isVisible=${info.isVisible()} " +
+ "visible=${info.visible} " +
+ "isFocused=${info.isFocused} " +
+ "isSleeping=${info.isSleeping} " +
+ "isRunning=${info.isRunning} " +
+ "windowMode=${windowingModeToString(info.windowingMode)} " +
+ "activityType=${activityTypeToString(info.activityType)} " +
+ "topActivity=${info.topActivity} " +
+ "topActivityInfo=${info.topActivityInfo} " +
+ "numActivities=${info.numActivities} " +
+ "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
+ "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
+ "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
+ "childTaskNames=${Arrays.toString(info.childTaskNames)}"
+ )
+
+ for (j in 0 until info.childTaskIds.size) {
+ Log.d(TAG, " *** [$j] ******")
+ Log.d(TAG, " *** childTaskIds[$j]: ${info.childTaskIds[j]}")
+ Log.d(TAG, " *** childTaskUserIds[$j]: ${info.childTaskUserIds[j]}")
+ Log.d(TAG, " *** childTaskBounds[$j]: ${info.childTaskBounds[j]}")
+ Log.d(TAG, " *** childTaskNames[$j]: ${info.childTaskNames[j]}")
+ }
+ }
+ }
+
+ private suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
+ withContext(bgDispatcher) {
+ try {
+ atmService.getAllRootTaskInfosOnDisplay(displayId)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "getAllRootTaskInfosOnDisplay", e)
+ listOf()
+ }
+ }
+
+ private suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
+ proxyConnector
+ .postForResult { it.isNotificationShadeExpanded }
+ .whenComplete { expanded, error ->
+ if (error != null) {
+ Log.e(TAG, "isNotificationShadeExpanded", error)
+ }
+ k.resume(expanded ?: false)
+ }
+ }
+
+ companion object {
+ const val TAG: String = "ScreenshotPolicyImpl"
+ const val DEBUG: Boolean = false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
new file mode 100644
index 0000000..9654e03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.screenshot
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import android.util.Log
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import javax.inject.Inject
+
+/**
+ * Provides state from the main SystemUI process on behalf of the Screenshot process.
+ */
+internal class ScreenshotProxyService @Inject constructor(
+ private val mExpansionMgr: PanelExpansionStateManager
+) : Service() {
+
+ private val mBinder: IBinder = object : IScreenshotProxy.Stub() {
+ /**
+ * @return true when the notification shade is partially or fully expanded.
+ */
+ override fun isNotificationShadeExpanded(): Boolean {
+ val expanded = !mExpansionMgr.isClosed()
+ Log.d(TAG, "isNotificationShadeExpanded(): $expanded")
+ return expanded
+ }
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ Log.d(TAG, "onBind: $intent")
+ return mBinder
+ }
+
+ companion object {
+ const val TAG = "ScreenshotProxyService"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 7bf3217..a8993bc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -22,6 +22,7 @@
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
import static com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR;
+import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SERVICE;
@@ -97,7 +98,7 @@
};
/** Informs about coarse grained state of the Controller. */
- interface RequestCallback {
+ public interface RequestCallback {
/** Respond to the current request indicating the screenshot request failed. */
void reportError();
@@ -124,6 +125,7 @@
mBgExecutor = bgExecutor;
mFeatureFlags = featureFlags;
mFeatureFlags.addListener(SCREENSHOT_REQUEST_PROCESSOR, FlagEvent::requestNoRestart);
+ mFeatureFlags.addListener(SCREENSHOT_WORK_PROFILE_POLICY, FlagEvent::requestNoRestart);
mProcessor = processor;
}
@@ -229,49 +231,57 @@
if (mFeatureFlags.isEnabled(SCREENSHOT_REQUEST_PROCESSOR)) {
Log.d(TAG, "handleMessage: Using request processor");
- mProcessor.processRequest(screenshotRequest, uriConsumer, requestCallback);
+ mProcessor.processAsync(screenshotRequest,
+ (request) -> dispatchToController(request, uriConsumer, requestCallback));
return true;
}
- switch (screenshotRequest.getType()) {
+ dispatchToController(screenshotRequest, uriConsumer, requestCallback);
+ return true;
+ }
+
+ private void dispatchToController(ScreenshotHelper.ScreenshotRequest request,
+ Consumer<Uri> uriConsumer, RequestCallback callback) {
+
+ ComponentName topComponent = request.getTopComponent();
+
+ switch (request.getType()) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
}
- mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback);
break;
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
}
- mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, callback);
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
- screenshotRequest.getBitmapBundle());
- Rect screenBounds = screenshotRequest.getBoundsInScreen();
- Insets insets = screenshotRequest.getInsets();
- int taskId = screenshotRequest.getTaskId();
- int userId = screenshotRequest.getUserId();
+ request.getBitmapBundle());
+ Rect screenBounds = request.getBoundsInScreen();
+ Insets insets = request.getInsets();
+ int taskId = request.getTaskId();
+ int userId = request.getUserId();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
- requestCallback.reportError();
+ callback.reportError();
} else {
mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
- taskId, userId, topComponent, uriConsumer, requestCallback);
+ taskId, userId, topComponent, uriConsumer, callback);
}
break;
default:
- Log.w(TAG, "Invalid screenshot option: " + msg.what);
- return false;
+ Log.w(TAG, "Invalid screenshot option: " + request.getType());
}
- return true;
}
private static void sendComplete(Messenger target) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 3e442587..fdb0100 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -20,6 +20,9 @@
import com.android.systemui.screenshot.ImageCapture;
import com.android.systemui.screenshot.ImageCaptureImpl;
+import com.android.systemui.screenshot.ScreenshotPolicy;
+import com.android.systemui.screenshot.ScreenshotPolicyImpl;
+import com.android.systemui.screenshot.ScreenshotProxyService;
import com.android.systemui.screenshot.TakeScreenshotService;
import dagger.Binds;
@@ -33,12 +36,20 @@
@Module
public abstract class ScreenshotModule {
- /** */
@Binds
@IntoMap
@ClassKey(TakeScreenshotService.class)
- public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
+ abstract Service bindTakeScreenshotService(TakeScreenshotService service);
@Binds
- public abstract ImageCapture bindImageCapture(ImageCaptureImpl capture);
+ @IntoMap
+ @ClassKey(ScreenshotProxyService.class)
+ abstract Service bindScreenshotProxyService(ScreenshotProxyService service);
+
+ @Binds
+ abstract ScreenshotPolicy bindScreenshotPolicyImpl(ScreenshotPolicyImpl impl);
+
+ @Binds
+ abstract ImageCapture bindImageCaptureImpl(ImageCaptureImpl capture);
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 65ba5ad..e754d5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -512,7 +512,8 @@
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
} else {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
- mUpdateMonitor.awakenFromDream();
+ // Don't call awaken from Dream here. In order to avoid flickering, wait until
+ // later to awaken.
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
mKeyguardViewMediator.onWakeAndUnlocking();
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 4c9c75b..103e4f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -27,6 +27,7 @@
import androidx.collection.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -39,6 +40,7 @@
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
@@ -107,8 +109,10 @@
GroupMembershipManager groupMembershipManager,
VisualStabilityProvider visualStabilityProvider,
ConfigurationController configurationController,
- @Main Handler handler) {
- super(context, logger, handler);
+ @Main Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
+ super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
Resources resources = mContext.getResources();
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
statusBarStateController.addCallback(mStatusBarStateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 699414c..e4e59a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -32,7 +32,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
@@ -81,12 +80,15 @@
}
}
- public HeadsUpManager(@NonNull final Context context, HeadsUpManagerLogger logger,
- @Main Handler handler) {
+ public HeadsUpManager(@NonNull final Context context,
+ HeadsUpManagerLogger logger,
+ @Main Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
super(logger, handler);
mContext = context;
- mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
- mUiEventLogger = Dependency.get(UiEventLogger.class);
+ mAccessibilityMgr = accessibilityManagerWrapper;
+ mUiEventLogger = uiEventLogger;
Resources resources = context.getResources();
mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 094490b..adef182 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -244,7 +244,8 @@
final int currentUser = mUserTracker.getUserId();
final boolean hadWallpaperColors = mCurrentColors.get(userId) != null;
int latestWallpaperType = getLatestWallpaperType(userId);
- if ((flags & latestWallpaperType) != 0) {
+ boolean eventForLatestWallpaper = (flags & latestWallpaperType) != 0;
+ if (eventForLatestWallpaper) {
mCurrentColors.put(userId, wallpaperColors);
if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
}
@@ -280,14 +281,19 @@
currentUser);
boolean isDestinationBoth = (flags == (WallpaperManager.FLAG_SYSTEM
| WallpaperManager.FLAG_LOCK));
+ boolean isDestinationHomeOnly = (flags == WallpaperManager.FLAG_SYSTEM);
try {
JSONObject jsonObject = (overlayPackageJson == null) ? new JSONObject()
: new JSONObject(overlayPackageJson);
// The latest applied wallpaper should be the source of system colors when:
// There is not preset color applied and the incoming wallpaper color is not applied
- if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
- && ((flags & latestWallpaperType) != 0 && !isSeedColorSet(jsonObject,
- wallpaperColors))) {
+ String wallpaperPickerColorSource = jsonObject.optString(OVERLAY_COLOR_SOURCE);
+ boolean userChosePresetColor = COLOR_SOURCE_PRESET.equals(wallpaperPickerColorSource);
+ boolean userChoseLockScreenColor = COLOR_SOURCE_LOCK.equals(wallpaperPickerColorSource);
+ boolean preserveLockScreenColor = isDestinationHomeOnly && userChoseLockScreenColor;
+
+ if (!userChosePresetColor && !preserveLockScreenColor && eventForLatestWallpaper
+ && !isSeedColorSet(jsonObject, wallpaperColors)) {
mSkipSettingChange = true;
if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
@@ -642,7 +648,7 @@
}
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
- mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
+ mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[]{
mSecondaryOverlay, mNeutralOverlay
}, currentUser, managedProfiles);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 0fe10cb..abffe555 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -26,6 +26,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
@@ -63,6 +64,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -173,7 +175,9 @@
GroupMembershipManager groupManager,
VisualStabilityProvider visualStabilityProvider,
ConfigurationController configurationController,
- @Main Handler handler) {
+ @Main Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
return new HeadsUpManagerPhone(
context,
headsUpManagerLogger,
@@ -182,7 +186,9 @@
groupManager,
visualStabilityProvider,
configurationController,
- handler
+ handler,
+ accessibilityManagerWrapper,
+ uiEventLogger
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 4c76270..aeab2df 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -38,6 +38,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.ZenModeConfig;
import android.util.Log;
@@ -101,6 +102,7 @@
private final ShadeController mShadeController;
private final IStatusBarService mBarService;
private final INotificationManager mNotificationManager;
+ private final IDreamManager mDreamManager;
private final NotificationVisibilityProvider mVisibilityProvider;
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final NotificationLockscreenUserManager mNotifUserManager;
@@ -126,6 +128,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -144,6 +147,7 @@
shadeController,
statusBarService,
notificationManager,
+ dreamManager,
visibilityProvider,
interruptionStateProvider,
zenModeController,
@@ -167,6 +171,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -182,6 +187,7 @@
mNotificationShadeWindowController = notificationShadeWindowController;
mShadeController = shadeController;
mNotificationManager = notificationManager;
+ mDreamManager = dreamManager;
mVisibilityProvider = visibilityProvider;
mNotificationInterruptStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
@@ -203,7 +209,7 @@
@Override
public void onKeyguardShowingChanged() {
boolean isUnlockedShade = !keyguardStateController.isShowing()
- && !keyguardStateController.isOccluded();
+ && !isDreamingOrInPreview();
bubbles.onStatusBarStateChanged(isUnlockedShade);
}
});
@@ -397,6 +403,15 @@
mBubbles.setSysuiProxy(mSysuiProxy);
}
+ private boolean isDreamingOrInPreview() {
+ try {
+ return mDreamManager.isDreamingOrInPreview();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query dream manager.", e);
+ return false;
+ }
+ }
+
private void setupNotifPipeline() {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 763a5cb..ba28045 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -53,7 +53,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
- <application android:debuggable="true" android:largeHeap="true">
+ <application android:debuggable="true" android:largeHeap="true"
+ android:enableOnBackInvokedCallback="true" >
<uses-library android:name="android.test.runner" />
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 141a213..b42b769 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -42,8 +42,11 @@
import android.testing.TestableLooper;
import android.view.GestureDetector;
import android.view.IWindowManager;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -73,6 +76,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -117,6 +122,8 @@
@Mock private CentralSurfaces mCentralSurfaces;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
+ @Mock private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
private TestableLooper mTestableLooper;
@@ -203,6 +210,58 @@
}
@Test
+ public void testPredictiveBackCallbackRegisteredAndUnregistered() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+ GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+ dialog.setBackDispatcherOverride(mOnBackInvokedDispatcher);
+ dialog.create();
+ mTestableLooper.processAllMessages();
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any());
+ dialog.onDetachedFromWindow();
+ mTestableLooper.processAllMessages();
+ verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(any());
+ }
+
+ @Test
+ public void testPredictiveBackInvocationDismissesDialog() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+ GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+ dialog.create();
+ dialog.show();
+ mTestableLooper.processAllMessages();
+ dialog.getWindow().injectInputEvent(
+ new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
+ dialog.getWindow().injectInputEvent(
+ new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
+ mTestableLooper.processAllMessages();
+ verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK);
+ assertThat(dialog.isShowing()).isFalse();
+ }
+
+ @Test
public void testSingleTap_logAndDismiss() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index fcfef4a4..c41fac7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -16,19 +16,22 @@
package com.android.systemui.media
+import android.provider.Settings
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import org.junit.Before
@@ -37,11 +40,12 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
class KeyguardMediaControllerTest : SysuiTestCase() {
@Mock
@@ -53,31 +57,33 @@
@Mock
private lateinit var configurationController: ConfigurationController
- @Mock
- private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@JvmField @Rule
val mockito = MockitoJUnit.rule()
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
private val hostView = UniqueObjectHostView(context)
+ private val settings = FakeSettings()
private lateinit var keyguardMediaController: KeyguardMediaController
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fakeHandler: FakeHandler
@Before
fun setup() {
// default state is positive, media should show up
whenever(mediaHost.visible).thenReturn(true)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
- .thenReturn(true)
whenever(mediaHost.hostView).thenReturn(hostView)
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
+ testableLooper = TestableLooper.get(this)
+ fakeHandler = FakeHandler(testableLooper.looper)
keyguardMediaController = KeyguardMediaController(
mediaHost,
bypassController,
statusBarStateController,
- notificationLockscreenUserManager,
context,
- configurationController
+ settings,
+ fakeHandler,
+ configurationController,
)
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
keyguardMediaController.useSplitShade = false
@@ -106,9 +112,8 @@
}
@Test
- fun testHiddenOnKeyguard_whenNotificationsAreHidden() {
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
- .thenReturn(false)
+ fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
keyguardMediaController.refreshMediaPosition()
@@ -116,6 +121,15 @@
}
@Test
+ fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
+
+ keyguardMediaController.refreshMediaPosition()
+
+ assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
+ }
+
+ @Test
fun testActivatesSplitShadeContainerInSplitShadeMode() {
val splitShadeContainer = FrameLayout(context)
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 1cce7cf..d1ed8e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -50,11 +50,10 @@
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
-import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
@@ -287,6 +286,30 @@
}
@Test
+ fun testOnNotificationAdded_hasSubstituteName_isUsed() {
+ val subName = "Substitute Name"
+ val notif = SbnBuilder().run {
+ modifyNotification(context).also {
+ it.extras = Bundle().apply {
+ putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName)
+ }
+ it.setStyle(MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ })
+ }
+ build()
+ }
+
+ mediaDataManager.onNotificationAdded(KEY, notif)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
+ eq(0), eq(false))
+
+ assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
+ }
+
+ @Test
fun testLoadMediaDataInBg_invalidTokenNoCrash() {
val bundle = Bundle()
// wrong data type
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 369913d..18bfd04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.graphics.Rect
+import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.ViewGroup
@@ -30,7 +31,6 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.testing.FakeNotifPanelEvents
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -38,6 +38,8 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertNotNull
import org.junit.Before
@@ -53,7 +55,6 @@
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@@ -68,7 +69,6 @@
@Mock private lateinit var bypassController: KeyguardBypassController
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
- @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@@ -82,37 +82,42 @@
@JvmField
@Rule
val mockito = MockitoJUnit.rule()
- private lateinit var mediaHiearchyManager: MediaHierarchyManager
+ private lateinit var mediaHierarchyManager: MediaHierarchyManager
private lateinit var mediaFrame: ViewGroup
private val configurationController = FakeConfigurationController()
private val notifPanelEvents = FakeNotifPanelEvents()
+ private val settings = FakeSettings()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fakeHandler: FakeHandler
@Before
fun setup() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, false)
mediaFrame = FrameLayout(context)
- `when`(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
- mediaHiearchyManager = MediaHierarchyManager(
+ testableLooper = TestableLooper.get(this)
+ fakeHandler = FakeHandler(testableLooper.looper)
+ whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
+ mediaHierarchyManager = MediaHierarchyManager(
context,
statusBarStateController,
keyguardStateController,
bypassController,
mediaCarouselController,
- notificationLockscreenUserManager,
keyguardViewController,
dreamOverlayStateController,
configurationController,
wakefulnessLifecycle,
notifPanelEvents,
- )
+ settings,
+ fakeHandler,)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
- `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
- `when`(mediaCarouselController.mediaCarouselScrollHandler)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
@@ -122,30 +127,30 @@
}
private fun setupHost(host: MediaHost, location: Int, top: Int) {
- `when`(host.location).thenReturn(location)
- `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
- `when`(host.hostView).thenReturn(uniqueObjectHostView)
- `when`(host.visible).thenReturn(true)
- mediaHiearchyManager.register(host)
+ whenever(host.location).thenReturn(location)
+ whenever(host.currentBounds).thenReturn(Rect(0, top, 0, top))
+ whenever(host.hostView).thenReturn(uniqueObjectHostView)
+ whenever(host.visible).thenReturn(true)
+ mediaHierarchyManager.register(host)
}
@Test
fun testHostViewSetOnRegister() {
- val host = mediaHiearchyManager.register(lockHost)
+ val host = mediaHierarchyManager.register(lockHost)
verify(lockHost).hostView = eq(host)
}
@Test
fun testBlockedWhenScreenTurningOff() {
// Let's set it onto QS:
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
observer.onStartedGoingToSleep()
clearInvocations(mediaCarouselController)
- mediaHiearchyManager.qsExpansion = 0.0f
+ mediaHierarchyManager.qsExpansion = 0.0f
verify(mediaCarouselController, times(0))
.onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
@@ -154,13 +159,13 @@
@Test
fun testAllowedWhenNotTurningOff() {
// Let's set it onto QS:
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
clearInvocations(mediaCarouselController)
- mediaHiearchyManager.qsExpansion = 0.0f
+ mediaHierarchyManager.qsExpansion = 0.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
}
@@ -170,7 +175,7 @@
goToLockscreen()
// Let's transition all the way to full shade
- mediaHiearchyManager.setTransitionToFullShadeAmount(100000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(100000f)
verify(mediaCarouselController).onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_QQS),
any(MediaHostState::class.java),
@@ -180,7 +185,7 @@
clearInvocations(mediaCarouselController)
// Let's go back to the lock screen
- mediaHiearchyManager.setTransitionToFullShadeAmount(0.0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(0.0f)
verify(mediaCarouselController).onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
any(MediaHostState::class.java),
@@ -189,7 +194,7 @@
anyLong())
// Let's make sure alpha is set
- mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(2.0f)
assertThat(mediaFrame.alpha).isNotEqualTo(1.0f)
}
@@ -198,7 +203,7 @@
goToLockscreen()
expandQS()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -206,7 +211,7 @@
fun calculateTransformationType_notOnLockscreen_returnsTransition() {
expandQS()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
}
@@ -216,7 +221,7 @@
goToLockscreen()
expandQS()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -226,9 +231,9 @@
enableSplitShade()
goToLockscreen()
expandQS()
- mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(10000f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
}
@@ -238,9 +243,9 @@
goToLockscreen()
expandQS()
whenever(lockHost.visible).thenReturn(false)
- mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(10000f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -250,9 +255,9 @@
goToLockscreen()
goToLockedShade()
expandQS()
- mediaHiearchyManager.setTransitionToFullShadeAmount(0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(0f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -261,13 +266,13 @@
goToLockscreen()
goToLockedShade()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@Test
fun testCloseGutsRelayToCarousel() {
- mediaHiearchyManager.closeGuts()
+ mediaHierarchyManager.closeGuts()
verify(mediaCarouselController).closeGuts()
}
@@ -281,7 +286,7 @@
@Test
fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
- assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+ assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
}
@Test
@@ -289,7 +294,7 @@
enterGuidedTransformation()
val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
- assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+ assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY())
.isEqualTo(expectedTranslation)
}
@@ -301,7 +306,7 @@
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
- assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isTrue()
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isTrue()
}
@Test
@@ -313,7 +318,7 @@
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
- assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse()
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
@Test
@@ -324,7 +329,7 @@
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
- assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse()
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
private fun enableSplitShade() {
@@ -336,9 +341,7 @@
private fun goToLockscreen() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
- true
- )
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
clearInvocations(mediaCarouselController)
}
@@ -352,13 +355,13 @@
}
private fun expandQS() {
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
}
private fun enterGuidedTransformation() {
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
goToLockscreen()
- mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(123f)
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 247316a..c101b9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.media.dream;
+import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -28,6 +30,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
@@ -50,6 +53,9 @@
@Mock
MediaDreamComplication mComplication;
+ @Mock
+ FeatureFlags mFeatureFlags;
+
final String mKey = "key";
final String mOldKey = "old_key";
@@ -59,21 +65,18 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
+ when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(true);
}
@Test
public void testComplicationAddition() {
final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
- mDreamOverlayStateController, mComplication);
+ mDreamOverlayStateController, mComplication, mFeatureFlags);
sentinel.start();
- ArgumentCaptor<MediaDataManager.Listener> listenerCaptor =
- ArgumentCaptor.forClass(MediaDataManager.Listener.class);
- verify(mMediaDataManager).addListener(listenerCaptor.capture());
-
- final MediaDataManager.Listener listener = listenerCaptor.getValue();
-
+ final MediaDataManager.Listener listener = captureMediaDataListener();
when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */ true,
/* receivedSmartspaceCardLatency= */ 0, /* isSsReactived= */ false);
@@ -92,4 +95,27 @@
verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
}
+ @Test
+ public void testMediaDreamSentinel_mediaComplicationDisabled_doNotAddComplication() {
+ when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
+
+ final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+ mDreamOverlayStateController, mComplication, mFeatureFlags);
+
+ sentinel.start();
+
+ final MediaDataManager.Listener listener = captureMediaDataListener();
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+ verify(mDreamOverlayStateController, never()).addComplication(any());
+ }
+
+ private MediaDataManager.Listener captureMediaDataListener() {
+ final ArgumentCaptor<MediaDataManager.Listener> listenerCaptor =
+ ArgumentCaptor.forClass(MediaDataManager.Listener.class);
+ verify(mMediaDataManager).addListener(listenerCaptor.capture());
+
+ return listenerCaptor.getValue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
new file mode 100644
index 0000000..447e28c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.screenshot
+
+import android.graphics.Bitmap
+import android.graphics.Rect
+
+internal class FakeImageCapture : ImageCapture {
+
+ var requestedDisplayId: Int? = null
+ var requestedDisplayCrop: Rect? = null
+ var requestedTaskId: Int? = null
+
+ var image: Bitmap? = null
+
+ override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {
+ requestedDisplayId = displayId
+ requestedDisplayCrop = crop
+ return image
+ }
+
+ override suspend fun captureTask(taskId: Int): Bitmap? {
+ requestedTaskId = taskId
+ return image
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
new file mode 100644
index 0000000..28d53c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+
+internal class FakeScreenshotPolicy : ScreenshotPolicy {
+
+ private val userTypes = mutableMapOf<Int, Boolean>()
+ private val contentInfo = mutableMapOf<Int, DisplayContentInfo?>()
+
+ fun setManagedProfile(userId: Int, managedUser: Boolean) {
+ userTypes[userId] = managedUser
+ }
+ override suspend fun isManagedProfile(userId: Int): Boolean {
+ return userTypes[userId] ?: error("No managedProfile value set for userId $userId")
+ }
+
+ fun setDisplayContentInfo(userId: Int, contentInfo: DisplayContentInfo) {
+ this.contentInfo[userId] = contentInfo
+ }
+
+ override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
+ return contentInfo[displayId] ?: error("No DisplayContentInfo set for displayId $displayId")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
index ce3f20d..00f3808 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
@@ -27,6 +27,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,7 +39,10 @@
class ImageCaptureImplTest : SysuiTestCase() {
private val displayManager = mock<DisplayManager>()
private val atmService = mock<IActivityTaskManager>()
- private val capture = TestableImageCaptureImpl(displayManager, atmService)
+ private val capture = TestableImageCaptureImpl(
+ displayManager,
+ atmService,
+ Dispatchers.Unconfined)
@Test
fun captureDisplayWithCrop() {
@@ -59,9 +64,10 @@
class TestableImageCaptureImpl(
displayManager: DisplayManager,
- atmService: IActivityTaskManager
+ atmService: IActivityTaskManager,
+ bgDispatcher: CoroutineDispatcher
) :
- ImageCaptureImpl(displayManager, atmService) {
+ ImageCaptureImpl(displayManager, atmService, bgDispatcher) {
var token: IBinder? = null
var width: Int? = null
@@ -81,4 +87,4 @@
return ScreenshotHardwareBuffer(null, null, false, false)
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 024d3bd..48fbd35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -22,86 +22,253 @@
import android.graphics.Insets
import android.graphics.Rect
import android.hardware.HardwareBuffer
-import android.net.Uri
+import android.os.Bundle
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-
+import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
+import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
import com.google.common.truth.Truth.assertThat
-import java.util.function.Consumer
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
import org.junit.Test
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.isNull
+
+private const val USER_ID = 1
+private const val TASK_ID = 1
class RequestProcessorTest {
- private val controller = mock<ScreenshotController>()
- private val bitmapCaptor = argumentCaptor<Bitmap>()
+ private val imageCapture = FakeImageCapture()
+ private val component = ComponentName("android.test", "android.test.Component")
+ private val bounds = Rect(25, 25, 75, 75)
+ private val scope = CoroutineScope(Dispatchers.Unconfined)
+ private val dispatcher = Dispatchers.Unconfined
+ private val policy = FakeScreenshotPolicy()
+ private val flags = FakeFeatureFlags()
+
+ /** Tests the Java-compatible function wrapper, ensures callback is invoked. */
@Test
- fun testFullScreenshot() {
+ fun testProcessAsync() {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
- val processor = RequestProcessor(controller)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
- processor.processRequest(request, onSavedListener, callback)
+ var result: ScreenshotRequest? = null
+ var callbackCount = 0
+ val callback: (ScreenshotRequest) -> Unit = { processedRequest: ScreenshotRequest ->
+ result = processedRequest
+ callbackCount++
+ }
- verify(controller).takeScreenshotFullscreen(/* topComponent */ isNull(),
- eq(onSavedListener), eq(callback))
+ // runs synchronously, using Unconfined Dispatcher
+ processor.processAsync(request, callback)
+
+ // Callback invoked once returning the same request (no changes)
+ assertThat(callbackCount).isEqualTo(1)
+ assertThat(result).isEqualTo(request)
}
@Test
- fun testSelectedRegionScreenshot() {
+ fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testFullScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ // Indicate that the primary content belongs to a normal user
+ policy.setManagedProfile(USER_ID, false)
+ policy.setDisplayContentInfo(
+ policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // Request has topComponent added, but otherwise unchanged.
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testFullScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ // Provide a fake task bitmap when asked
+ val bitmap = makeHardwareBitmap(100, 100)
+ imageCapture.image = bitmap
+
+ // Indicate that the primary content belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // Expect a task snapshot is taken, overriding the full screen mode
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
+ assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
+ assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
+ assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
+ assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
+ assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
+ assertThat(processedRequest.userId).isEqualTo(USER_ID)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testSelectedRegionScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
- val processor = RequestProcessor(controller)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
- processor.processRequest(request, onSavedListener, callback)
+ val processedRequest = processor.process(request)
- verify(controller).takeScreenshotPartial(/* topComponent */ isNull(),
- eq(onSavedListener), eq(callback))
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testSelectedRegionScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ policy.setManagedProfile(USER_ID, false)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val processedRequest = processor.process(request)
+
+ // Request has topComponent added, but otherwise unchanged.
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
}
@Test
- fun testProvidedImageScreenshot() {
- val taskId = 1111
- val userId = 2222
- val bounds = Rect(50, 50, 150, 150)
- val topComponent = ComponentName("test", "test")
- val processor = RequestProcessor(controller)
+ fun testSelectedRegionScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
- val buffer = HardwareBuffer.create(100, 100, HardwareBuffer.RGBA_8888, 1,
- HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
- val bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
+ // Provide a fake task bitmap when asked
+ val bitmap = makeHardwareBitmap(100, 100)
+ imageCapture.image = bitmap
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ // Indicate that the primary content belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val processedRequest = processor.process(request)
+
+ // Expect a task snapshot is taken, overriding the selected region mode
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
+ assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
+ assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
+ assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
+ assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
+ assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
+ assertThat(processedRequest.userId).isEqualTo(USER_ID)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testProvidedImageScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val bitmap = makeHardwareBitmap(100, 100)
val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
- bitmapBundle, bounds, Insets.NONE, taskId, userId, topComponent)
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
+ val processedRequest = processor.process(request)
- processor.processRequest(request, onSavedListener, callback)
-
- verify(controller).handleImageAsScreenshot(
- bitmapCaptor.capture(), eq(bounds), eq(Insets.NONE), eq(taskId), eq(userId),
- eq(topComponent), eq(onSavedListener), eq(callback)
- )
-
- assertThat(bitmapCaptor.value.equalsHardwareBitmap(bitmap)).isTrue()
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
}
- private fun Bitmap.equalsHardwareBitmap(bitmap: Bitmap): Boolean {
- return bitmap.hardwareBuffer == this.hardwareBuffer &&
- bitmap.colorSpace == this.colorSpace
+ @Test
+ fun testProvidedImageScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ policy.setManagedProfile(USER_ID, false)
+
+ val bitmap = makeHardwareBitmap(100, 100)
+ val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+
+ val processedRequest = processor.process(request)
+
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testProvidedImageScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ // Indicate that the screenshot belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+
+ val bitmap = makeHardwareBitmap(100, 100)
+ val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+
+ val processedRequest = processor.process(request)
+
+ // Work profile, but already a task snapshot, so no changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
+ val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
+ return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
+ }
+
+ private fun Bitmap.equalsHardwareBitmapBundle(bundle: Bundle): Boolean {
+ val provided = bundleToHardwareBitmap(bundle)
+ return provided.hardwareBuffer == this.hardwareBuffer &&
+ provided.colorSpace == this.colorSpace
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
index 64d0256..214ba16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
@@ -98,7 +98,7 @@
@Test
fun testPrepareDialogForApp_onlyDefaultChannel() {
- group.addChannel(channelDefault)
+ group.channels = listOf(channelDefault)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channelDefault), appIcon, clickListener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c25737d..cc4cbbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -48,6 +48,7 @@
import android.widget.RemoteViews;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -75,6 +76,7 @@
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
@@ -145,7 +147,9 @@
mock(GroupMembershipManager.class),
mock(VisualStabilityProvider.class),
mock(ConfigurationControllerImpl.class),
- new Handler(mTestLooper.getLooper())
+ new Handler(mTestLooper.getLooper()),
+ mock(AccessibilityManagerWrapper.class),
+ mock(UiEventLogger.class)
);
mIconManager = new IconManager(
mock(CommonNotifCollection.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index ac3d0c2..e252401 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -29,6 +29,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
@@ -65,6 +66,8 @@
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardBypassController mBypassController;
@Mock private ConfigurationControllerImpl mConfigurationController;
+ @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
+ @Mock private UiEventLogger mUiEventLogger;
private boolean mLivesPastNormalTime;
private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
@@ -76,7 +79,9 @@
StatusBarStateController statusBarStateController,
KeyguardBypassController keyguardBypassController,
ConfigurationController configurationController,
- Handler handler
+ Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger
) {
super(
context,
@@ -86,7 +91,9 @@
groupManager,
visualStabilityProvider,
configurationController,
- handler
+ handler,
+ accessibilityManagerWrapper,
+ uiEventLogger
);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
@@ -116,7 +123,9 @@
mStatusBarStateController,
mBypassController,
mConfigurationController,
- mTestHandler
+ mTestHandler,
+ mAccessibilityManagerWrapper,
+ mUiEventLogger
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index e2b9a9e..9764b8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -63,7 +63,6 @@
private static final int TEST_A11Y_AUTO_DISMISS_TIME = 600;
private static final int TEST_A11Y_TIMEOUT_TIME = 5_000;
- private AccessibilityManagerWrapper mAccessibilityMgr;
private HeadsUpManager mHeadsUpManager;
private boolean mLivesPastNormalTime;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -72,10 +71,15 @@
@Mock private StatusBarNotification mSbn;
@Mock private Notification mNotification;
@Mock private HeadsUpManagerLogger mLogger;
+ @Mock private AccessibilityManagerWrapper mAccessibilityMgr;
private final class TestableHeadsUpManager extends HeadsUpManager {
- TestableHeadsUpManager(Context context, HeadsUpManagerLogger logger, Handler handler) {
- super(context, logger, handler);
+ TestableHeadsUpManager(Context context,
+ HeadsUpManagerLogger logger,
+ Handler handler,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
+ super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
@@ -88,13 +92,11 @@
@Before
public void setUp() {
initMocks(this);
- mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
- mDependency.injectTestDependency(UiEventLogger.class, mUiEventLoggerFake);
when(mEntry.getSbn()).thenReturn(mSbn);
when(mSbn.getNotification()).thenReturn(mNotification);
-
super.setUp();
- mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger, mTestHandler);
+ mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger, mTestHandler,
+ mAccessibilityMgr, mUiEventLoggerFake);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index b7f38f1..50259b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -310,7 +310,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWithNewHomeWallpapers() {
+ public void onWallpaperColorsChanged_resetThemeWithNewHomeWallpapers() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -345,6 +345,61 @@
}
@Test
+ public void onWallpaperColorsChanged_keepsThemeWhenSetFromLockScreen() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(20);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(21);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
+ verify(mSecureSettings, never()).putStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any(), anyInt());
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_resetLockScreenThemeWhenBothSet() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(20);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(21);
+
+ mColorsListener.getValue().onColorsChanged(mainColors,
+ WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK,
+ USER_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(),
+ anyInt());
+ assertThat(updatedSetting.getValue().contains(
+ "android.theme.customization.color_both\":\"1")).isTrue();
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onSettingChanged_honorThemeStyle() {
when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
List<Style> validStyles = Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT,
@@ -381,7 +436,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWithNewHomeAndLockWallpaper() {
+ public void onWallpaperColorsChanged_resetThemeWithNewHomeAndLockWallpaper() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -450,7 +505,7 @@
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
String jsonString =
- "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ "{\"android.theme.customization.color_source\":\"home_wallpaper\","
+ "\"android.theme.customization.system_palette\":\"A16B00\","
+ "\"android.theme.customization.accent_color\":\"A16B00\","
+ "\"android.theme.customization.color_index\":\"2\"}";
@@ -476,7 +531,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWhenFromLatestWallpaper() {
+ public void onWallpaperColorsChanged_resetThemeWhenFromLatestWallpaper() {
// Should ask for a new theme when the colors of the last applied wallpaper change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 18acf3f..8f2b715 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -63,6 +63,7 @@
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
@@ -204,6 +205,8 @@
private ArgumentCaptor<IntentFilter> mFilterArgumentCaptor;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
+ @Captor
+ private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
@@ -240,6 +243,8 @@
@Mock
private IStatusBarService mStatusBarService;
@Mock
+ private IDreamManager mIDreamManager;
+ @Mock
private NotificationVisibilityProvider mVisibilityProvider;
@Mock
private LauncherApps mLauncherApps;
@@ -371,10 +376,11 @@
mContext,
mBubbleController.asBubbles(),
mNotificationShadeWindowController,
- mock(KeyguardStateController.class),
+ mKeyguardStateController,
mShadeController,
mStatusBarService,
mock(INotificationManager.class),
+ mIDreamManager,
mVisibilityProvider,
interruptionStateProvider,
mZenModeController,
@@ -391,6 +397,25 @@
verify(mNotifPipeline, atLeastOnce())
.addCollectionListener(mNotifListenerCaptor.capture());
mEntryListener = mNotifListenerCaptor.getValue();
+
+ // Get a reference to KeyguardStateController.Callback
+ verify(mKeyguardStateController, atLeastOnce())
+ .addCallback(mKeyguardStateControllerCallbackCaptor.capture());
+ }
+
+ @Test
+ public void dreamingHidesBubbles() throws RemoteException {
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertTrue(mBubbleController.hasBubbles());
+ assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
+
+ when(mIDreamManager.isDreamingOrInPreview()).thenReturn(true); // dreaming is happening
+ when(mKeyguardStateController.isShowing()).thenReturn(false); // device is unlocked
+ KeyguardStateController.Callback callback =
+ mKeyguardStateControllerCallbackCaptor.getValue();
+ callback.onKeyguardShowingChanged();
+
+ assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c8519c1..297e6a2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18414,11 +18414,11 @@
attributionSource.getUid()), Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, new AttributionSource(shellUid, /*pid*/ -1,
+ return superImpl.apply(code, new AttributionSource(shellUid,
"com.android.shell", attributionSource.getAttributionTag(),
- attributionSource.getToken(), /*renouncedPermissions*/ null,
- attributionSource.getNext()), shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, skiProxyOperation);
+ attributionSource.getToken(), attributionSource.getNext()),
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ skiProxyOperation);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -18465,13 +18465,12 @@
attributionSource.getUid()), Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, new AttributionSource(shellUid, /*pid*/ -1,
+ return superImpl.apply(code, new AttributionSource(shellUid,
"com.android.shell", attributionSource.getAttributionTag(),
- attributionSource.getToken(), /*renouncedPermissions*/ null,
- attributionSource.getNext()), startIfModeDefault,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
- attributionChainId);
+ attributionSource.getToken(), attributionSource.getNext()),
+ startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
+ proxiedAttributionFlags, attributionChainId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -18490,10 +18489,10 @@
attributionSource.getUid()), Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- superImpl.apply(code, new AttributionSource(shellUid, /*pid*/ -1,
+ superImpl.apply(code, new AttributionSource(shellUid,
"com.android.shell", attributionSource.getAttributionTag(),
- attributionSource.getToken(), /*renouncedPermissions*/ null,
- attributionSource.getNext()), skipProxyOperation);
+ attributionSource.getToken(), attributionSource.getNext()),
+ skipProxyOperation);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b97aa5f..aa2a25b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6684,6 +6684,20 @@
}
}
+ // Ensure only allowed packages have a substitute app name
+ if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
+ int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
+ permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
+ if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
+ notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
+ if (DBG) {
+ Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name"
+ + " without holding perm "
+ + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
+ }
+ }
+ }
+
// Remote views? Are they too big?
checkRemoteViews(pkg, tag, id, notification);
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 477b8da..729c521 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -86,6 +86,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -1327,16 +1328,17 @@
return null;
}
NotificationChannelGroup group = r.groups.get(groupId).clone();
- group.setChannels(new ArrayList<>());
+ ArrayList channels = new ArrayList();
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
if (includeDeleted || !nc.isDeleted()) {
if (groupId.equals(nc.getGroup())) {
- group.addChannel(nc);
+ channels.add(nc);
}
}
}
+ group.setChannels(channels);
return group;
}
}
@@ -1349,7 +1351,10 @@
if (r == null) {
return null;
}
- return r.groups.get(groupId);
+ if (r.groups.get(groupId) != null) {
+ return r.groups.get(groupId).clone();
+ }
+ return null;
}
}
@@ -1357,44 +1362,48 @@
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
Objects.requireNonNull(pkg);
- Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
+ List<NotificationChannelGroup> groups = new ArrayList<>();
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
return ParceledListSlice.emptyList();
}
- NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ Map<String, ArrayList<NotificationChannel>> groupedChannels = new HashMap();
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
if (includeDeleted || !nc.isDeleted()) {
if (nc.getGroup() != null) {
if (r.groups.get(nc.getGroup()) != null) {
- NotificationChannelGroup ncg = groups.get(nc.getGroup());
- if (ncg == null) {
- ncg = r.groups.get(nc.getGroup()).clone();
- ncg.setChannels(new ArrayList<>());
- groups.put(nc.getGroup(), ncg);
-
- }
- ncg.addChannel(nc);
+ ArrayList<NotificationChannel> channels = groupedChannels.getOrDefault(
+ nc.getGroup(), new ArrayList<>());
+ channels.add(nc);
+ groupedChannels.put(nc.getGroup(), channels);
}
} else {
- nonGrouped.addChannel(nc);
+ ArrayList<NotificationChannel> channels = groupedChannels.getOrDefault(
+ null, new ArrayList<>());
+ channels.add(nc);
+ groupedChannels.put(null, channels);
}
}
}
- if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
- groups.put(null, nonGrouped);
- }
- if (includeEmpty) {
- for (NotificationChannelGroup group : r.groups.values()) {
- if (!groups.containsKey(group.getId())) {
- groups.put(group.getId(), group);
- }
+ for (NotificationChannelGroup group : r.groups.values()) {
+ ArrayList<NotificationChannel> channels =
+ groupedChannels.getOrDefault(group.getId(), new ArrayList<>());
+ if (includeEmpty || !channels.isEmpty()) {
+ NotificationChannelGroup clone = group.clone();
+ clone.setChannels(channels);
+ groups.add(clone);
}
}
- return new ParceledListSlice<>(new ArrayList<>(groups.values()));
+
+ if (includeNonGrouped && groupedChannels.containsKey(null)) {
+ NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ nonGrouped.setChannels(groupedChannels.get(null));
+ groups.add(nonGrouped);
+ }
+ return new ParceledListSlice<>(groups);
}
}
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index a878bfd..b3c7cc0 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -500,6 +500,13 @@
boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
@UserIdInt int userId);
+ /**
+ * @return true if the runtime app user enabled state and the install-time app manifest enabled
+ * state are both effectively enabled for the given app. Or if the app cannot be found,
+ * returns false.
+ */
+ boolean isApplicationEffectivelyEnabled(@NonNull String packageName, @UserIdInt int userId);
+
@Nullable
KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 8ec3d2b..7dc648c 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -5412,6 +5412,26 @@
}
}
+ @Override
+ public boolean isApplicationEffectivelyEnabled(@NonNull String packageName,
+ @UserIdInt int userId) {
+ try {
+ int appEnabledSetting = mSettings.getApplicationEnabledSetting(packageName, userId);
+ if (appEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) {
+ final AndroidPackage pkg = getPackage(packageName);
+ if (pkg == null) {
+ // Should not happen because getApplicationEnabledSetting would have thrown
+ return false;
+ }
+ return pkg.isEnabled();
+ } else {
+ return appEnabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
+ }
+ } catch (PackageManager.NameNotFoundException ignored) {
+ return false;
+ }
+ }
+
@Nullable
@Override
public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 025e973..87ab87d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -18,6 +18,7 @@
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.os.UserManager.DISALLOW_USER_SWITCH;
import android.Manifest;
import android.accounts.Account;
@@ -1885,6 +1886,19 @@
}
@Override
+ public boolean isUserSwitcherEnabled(@UserIdInt int mUserId) {
+ boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.USER_SWITCHER_ENABLED,
+ Resources.getSystem().getBoolean(com.android.internal
+ .R.bool.config_showUserSwitcherByDefault) ? 1 : 0) != 0;
+
+ return UserManager.supportsMultipleUsers()
+ && !hasUserRestriction(DISALLOW_USER_SWITCH, mUserId)
+ && !UserManager.isDeviceInDemoMode(mContext)
+ && multiUserSettingOn;
+ }
+
+ @Override
public boolean isRestricted(@UserIdInt int userId) {
if (userId != UserHandle.getCallingUserId()) {
checkCreateUsersPermission("query isRestricted for user " + userId);
@@ -2277,7 +2291,6 @@
originatingUserId, local);
localChanged = updateLocalRestrictionsForTargetUsersLR(originatingUserId, local,
updatedLocalTargetUserIds);
-
if (isDeviceOwner) {
// Remember the global restriction owner userId to be able to make a distinction
// in getUserRestrictionSource on who set local policies.
@@ -4804,41 +4817,59 @@
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
this::onPullAtom);
+ statsManager.setPullAtomCallback(
+ FrameworkStatsLog.MULTI_USER_INFO,
+ null, // use default PullAtomMetadata values
+ BackgroundThread.getExecutor(),
+ this::onPullAtom);
}
/** Writes a UserInfo pulled atom for each user on the device. */
private int onPullAtom(int atomTag, List<StatsEvent> data) {
- if (atomTag != FrameworkStatsLog.USER_INFO) {
- Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag);
- return android.app.StatsManager.PULL_SKIP;
- }
- final List<UserInfo> users = getUsersInternal(true, true, true);
- final int size = users.size();
- if (size > 1) {
- for (int idx = 0; idx < size; idx++) {
- final UserInfo user = users.get(idx);
- final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType);
- final String userTypeCustom = (userTypeStandard == FrameworkStatsLog
- .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN)
- ?
- user.userType : null;
+ if (atomTag == FrameworkStatsLog.USER_INFO) {
+ final List<UserInfo> users = getUsersInternal(true, true, true);
+ final int size = users.size();
+ if (size > 1) {
+ for (int idx = 0; idx < size; idx++) {
+ final UserInfo user = users.get(idx);
+ final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType);
+ final String userTypeCustom = (userTypeStandard == FrameworkStatsLog
+ .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN)
+ ?
+ user.userType : null;
- boolean isUserRunningUnlocked;
- synchronized (mUserStates) {
- isUserRunningUnlocked =
- mUserStates.get(user.id, -1) == UserState.STATE_RUNNING_UNLOCKED;
+ boolean isUserRunningUnlocked;
+ synchronized (mUserStates) {
+ isUserRunningUnlocked =
+ mUserStates.get(user.id, -1) == UserState.STATE_RUNNING_UNLOCKED;
+ }
+
+ data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.USER_INFO,
+ user.id,
+ userTypeStandard,
+ userTypeCustom,
+ user.flags,
+ user.creationTime,
+ user.lastLoggedInTime,
+ isUserRunningUnlocked
+ ));
+ }
+ }
+ } else if (atomTag == FrameworkStatsLog.MULTI_USER_INFO) {
+ if (UserManager.getMaxSupportedUsers() > 1) {
+ int deviceOwnerUserId = UserHandle.USER_NULL;
+
+ synchronized (mRestrictionsLock) {
+ deviceOwnerUserId = mDeviceOwnerUserId;
}
- data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.USER_INFO,
- user.id,
- userTypeStandard,
- userTypeCustom,
- user.flags,
- user.creationTime,
- user.lastLoggedInTime,
- isUserRunningUnlocked
- ));
+ data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.MULTI_USER_INFO,
+ UserManager.getMaxSupportedUsers(),
+ isUserSwitcherEnabled(deviceOwnerUserId)));
}
+ } else {
+ Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag);
+ return android.app.StatsManager.PULL_SKIP;
}
return android.app.StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 0a39e64..47a3705 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -25,6 +25,7 @@
import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
@@ -77,6 +78,7 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
final class VerifyingSession {
@@ -353,7 +355,7 @@
}
final int verifierUserId = verifierUser.getIdentifier();
- String[] requiredVerifierPackages = mPm.mRequiredVerifierPackages;
+ List<String> requiredVerifierPackages = Arrays.asList(mPm.mRequiredVerifierPackages);
boolean requiredVerifierPackagesOverridden = false;
// Allow verifier override for ADB installations which could already be unverified using
@@ -377,8 +379,7 @@
// are not adding a new way to disable verifications.
if (!isAdbVerificationEnabled(pkgLite, verifierUserId,
requestedDisableVerification)) {
- requiredVerifierPackages = adbVerifierOverridePackages.toArray(
- new String[adbVerifierOverridePackages.size()]);
+ requiredVerifierPackages = adbVerifierOverridePackages;
requiredVerifierPackagesOverridden = true;
}
}
@@ -397,6 +398,16 @@
*/
final Computer snapshot = mPm.snapshotComputer();
+ final int numRequiredVerifierPackages = requiredVerifierPackages.size();
+ for (int i = numRequiredVerifierPackages - 1; i >= 0; i--) {
+ if (!snapshot.isApplicationEffectivelyEnabled(requiredVerifierPackages.get(i),
+ SYSTEM_UID)) {
+ Slog.w(TAG,
+ "Required verifier: " + requiredVerifierPackages.get(i) + " is disabled");
+ requiredVerifierPackages.remove(i);
+ }
+ }
+
for (String requiredVerifierPackage : requiredVerifierPackages) {
final int requiredUid = snapshot.getPackageUid(requiredVerifierPackage,
MATCH_DEBUG_TRIAGED_MISSING, verifierUserId);
@@ -514,7 +525,7 @@
}
}
- if (requiredVerifierPackages.length == 0) {
+ if (requiredVerifierPackages.size() == 0) {
Slog.e(TAG, "No required verifiers");
return;
}
@@ -532,7 +543,7 @@
final Intent requiredIntent;
final String receiverPermission;
- if (!requiredVerifierPackagesOverridden || requiredVerifierPackages.length == 1) {
+ if (!requiredVerifierPackagesOverridden || requiredVerifierPackages.size() == 1) {
// Prod code OR test code+single verifier.
requiredIntent = new Intent(verification);
if (!requiredVerifierPackagesOverridden) {
@@ -657,7 +668,7 @@
* @return true if verification should be performed
*/
private boolean isVerificationEnabled(PackageInfoLite pkgInfoLite, int userId,
- String[] requiredVerifierPackages) {
+ List<String> requiredVerifierPackages) {
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 9c95769..7602d33 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -354,7 +354,7 @@
* Get op that controls the access related to the permission.
*
* <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location)
- * {@link AppOpsManager#sOpToSwitch share an op} to control the access.
+ * {@link AppOpsManager#opToSwitch(int)} share an op} to control the access.
*
* @param permission The permission
* @return The op that controls the access of the permission
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 51bf557..7dcfd8b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2082,21 +2082,22 @@
mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
@Override
- public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
+ public int onAppTransitionStartingLocked(boolean keyguardGoingAway,
+ boolean keyguardOccluding, long duration, long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
- return handleTransitionForKeyguardLw(false /* startKeyguardExitAnimation */,
- false /* notifyOccluded */);
+ // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI
+ // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't
+ // need to call IKeyguardService#keyguardGoingAway here.
+ return handleStartTransitionForKeyguardLw(keyguardGoingAway
+ && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation,
+ keyguardOccluding, duration);
}
@Override
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
- // When app KEYGUARD_GOING_AWAY or (UN)OCCLUDE app transition is canceled, we need
- // to trigger relevant IKeyguardService calls to sync keyguard status in
- // WindowManagerService and SysUI.
- handleTransitionForKeyguardLw(
- keyguardGoingAwayCancelled /* startKeyguardExitAnimation */,
- keyguardOccludedCancelled /* notifyOccluded */);
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
+ handleStartTransitionForKeyguardLw(
+ keyguardGoingAway, false /* keyguardOccludingStarted */,
+ 0 /* duration */);
}
});
@@ -3262,39 +3263,31 @@
mPendingKeyguardOccluded = occluded;
mKeyguardOccludedChanged = true;
} else {
- setKeyguardOccludedLw(occluded, true /* notify */);
+ setKeyguardOccludedLw(occluded, false /* force */,
+ false /* transitionStarted */);
}
}
@Override
- public int applyKeyguardOcclusionChange(boolean notify) {
+ public int applyKeyguardOcclusionChange(boolean transitionStarted) {
if (mKeyguardOccludedChanged) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
+ mPendingKeyguardOccluded);
- if (setKeyguardOccludedLw(mPendingKeyguardOccluded, notify)) {
+ if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */,
+ transitionStarted)) {
return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
}
}
return 0;
}
- /**
- * Called when keyguard related app transition starts, or cancelled.
- *
- * @param startKeyguardExitAnimation Trigger IKeyguardService#startKeyguardExitAnimation to
- * start keyguard exit animation.
- * @param notifyOccluded Trigger IKeyguardService#setOccluded binder call to notify whether
- * the top activity can occlude the keyguard or not.
- *
- * @return Whether the flags have changed and we have to redo the layout.
- */
- private int handleTransitionForKeyguardLw(boolean startKeyguardExitAnimation,
- boolean notifyOccluded) {
- final int redoLayout = applyKeyguardOcclusionChange(notifyOccluded);
+ private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway,
+ boolean keyguardOccluding, long duration) {
+ final int redoLayout = applyKeyguardOcclusionChange(keyguardOccluding);
if (redoLayout != 0) return redoLayout;
- if (startKeyguardExitAnimation) {
+ if (keyguardGoingAway) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation");
- startKeyguardExitAnimation(SystemClock.uptimeMillis());
+ startKeyguardExitAnimation(SystemClock.uptimeMillis(), duration);
}
return 0;
}
@@ -3526,18 +3519,28 @@
* Updates the occluded state of the Keyguard.
*
* @param isOccluded Whether the Keyguard is occluded by another window.
- * @param notify Notify keyguard occlude status change immediately via
- * {@link com.android.internal.policy.IKeyguardService}.
+ * @param force notify the occluded status to KeyguardService and update flags even though
+ * occlude status doesn't change.
+ * @param transitionStarted {@code true} if keyguard (un)occluded transition started.
* @return Whether the flags have changed and we have to redo the layout.
*/
- private boolean setKeyguardOccludedLw(boolean isOccluded, boolean notify) {
+ private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force,
+ boolean transitionStarted) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
mKeyguardOccludedChanged = false;
- if (isKeyguardOccluded() == isOccluded) {
+ if (isKeyguardOccluded() == isOccluded && !force) {
return false;
}
- mKeyguardDelegate.setOccluded(isOccluded, notify);
- return mKeyguardDelegate.isShowing();
+
+ final boolean showing = mKeyguardDelegate.isShowing();
+ final boolean animate = showing && !isOccluded;
+ // When remote animation is enabled for keyguard (un)occlude transition, KeyguardService
+ // uses remote animation start as a signal to update its occlusion status ,so we don't need
+ // to notify here.
+ final boolean notify = !WindowManagerService.sEnableRemoteKeyguardOccludeAnimation
+ || !transitionStarted;
+ mKeyguardDelegate.setOccluded(isOccluded, animate, notify);
+ return showing;
}
/** {@inheritDoc} */
@@ -4933,10 +4936,10 @@
}
@Override
- public void startKeyguardExitAnimation(long startTime) {
+ public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
if (mKeyguardDelegate != null) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
- mKeyguardDelegate.startKeyguardExitAnimation(startTime);
+ mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration);
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 2b04050..4f00992 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -171,10 +171,10 @@
void onKeyguardOccludedChangedLw(boolean occluded);
/**
- * @param notify {@code true} if the status change should be immediately notified via
- * {@link com.android.internal.policy.IKeyguardService}
+ * Applies a keyguard occlusion change if one happened.
+ * @param transitionStarted Whether keyguard (un)occlude transition is starting or not.
*/
- int applyKeyguardOcclusionChange(boolean notify);
+ int applyKeyguardOcclusionChange(boolean transitionStarted);
/**
* Interface to the Window Manager state associated with a particular
@@ -1129,10 +1129,11 @@
/**
* Notifies the keyguard to start fading out.
- * @param startTime the start time of the animation in uptime milliseconds
*
+ * @param startTime the start time of the animation in uptime milliseconds
+ * @param fadeoutDuration the duration of the exit animation, in milliseconds
*/
- void startKeyguardExitAnimation(long startTime);
+ void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
/**
* Called when System UI has been started.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 7737421..b79ac6f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -249,10 +249,10 @@
}
}
- public void setOccluded(boolean isOccluded, boolean notify) {
+ public void setOccluded(boolean isOccluded, boolean animate, boolean notify) {
if (mKeyguardService != null && notify) {
- if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
- mKeyguardService.setOccluded(isOccluded, false /* animate */);
+ if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
+ mKeyguardService.setOccluded(isOccluded, animate);
}
mKeyguardState.occluded = isOccluded;
}
@@ -394,9 +394,9 @@
}
}
- public void startKeyguardExitAnimation(long startTime) {
+ public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
if (mKeyguardService != null) {
- mKeyguardService.startKeyguardExitAnimation(startTime, 0);
+ mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 55175c5..7e94743 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -659,6 +659,9 @@
boolean mUseTransferredAnimation;
+ /** Whether we need to setup the animation to animate only within the letterbox. */
+ private boolean mNeedsLetterboxedAnimation;
+
/**
* @see #currentLaunchCanTurnScreenOn()
*/
@@ -1762,8 +1765,12 @@
mLetterboxUiController.layoutLetterbox(winHint);
}
- boolean hasWallpaperBackgroudForLetterbox() {
- return mLetterboxUiController.hasWallpaperBackgroudForLetterbox();
+ boolean hasWallpaperBackgroundForLetterbox() {
+ return mLetterboxUiController.hasWallpaperBackgroundForLetterbox();
+ }
+
+ void updateLetterboxSurface(WindowState winHint, Transaction t) {
+ mLetterboxUiController.updateLetterboxSurface(winHint, t);
}
void updateLetterboxSurface(WindowState winHint) {
@@ -5325,6 +5332,18 @@
commitVisibility(visible, performLayout, false /* fromTransition */);
}
+ void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
+ mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
+ }
+
+ boolean isNeedsLetterboxedAnimation() {
+ return mNeedsLetterboxedAnimation;
+ }
+
+ boolean isInLetterboxAnimation() {
+ return mNeedsLetterboxedAnimation && isAnimating();
+ }
+
/**
* Post process after applying an app transition animation.
*
@@ -7252,6 +7271,10 @@
.setParent(getAnimationLeashParent())
.setName(getSurfaceControl() + " - animation-bounds")
.setCallsite("ActivityRecord.createAnimationBoundsLayer");
+ if (mNeedsLetterboxedAnimation) {
+ // Needs to be an effect layer to support rounded corners
+ builder.setEffectLayer();
+ }
final SurfaceControl boundsLayer = builder.build();
t.show(boundsLayer);
return boundsLayer;
@@ -7289,6 +7312,11 @@
mAnimatingActivityRegistry.notifyStarting(this);
}
+ if (mNeedsLetterboxedAnimation) {
+ updateLetterboxSurface(findMainWindow(), t);
+ mNeedsAnimationBoundsLayer = true;
+ }
+
// If the animation needs to be cropped then an animation bounds layer is created as a
// child of the root pinned task or animation layer. The leash is then reparented to this
// new layer.
@@ -7311,6 +7339,17 @@
t.setLayer(leash, 0);
t.setLayer(mAnimationBoundsLayer, getLastLayer());
+ if (mNeedsLetterboxedAnimation) {
+ final int cornerRadius = mLetterboxUiController
+ .getRoundedCornersRadius(findMainWindow());
+
+ final Rect letterboxInnerBounds = new Rect();
+ getLetterboxInnerBounds(letterboxInnerBounds);
+
+ t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
+ .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
+ }
+
// Reparent leash to animation bounds layer.
t.reparent(leash, mAnimationBoundsLayer);
}
@@ -7424,6 +7463,12 @@
mAnimationBoundsLayer = null;
}
+ mNeedsAnimationBoundsLayer = false;
+ if (mNeedsLetterboxedAnimation) {
+ mNeedsLetterboxedAnimation = false;
+ updateLetterboxSurface(findMainWindow(), t);
+ }
+
if (mAnimatingActivityRegistry != null) {
mAnimatingActivityRegistry.notifyFinished(this);
}
@@ -7436,7 +7481,6 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
mTransit = TRANSIT_OLD_UNSET;
mTransitFlags = 0;
- mNeedsAnimationBoundsLayer = false;
setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
"ActivityRecord");
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0a4bc60d..de3b2a6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1486,6 +1486,7 @@
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ a.configChanges = ActivityInfo.CONFIG_ORIENTATION;
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 5a1afc4..20032d6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -789,7 +789,7 @@
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
-
+ r.lastLaunchTime = SystemClock.uptimeMillis();
r.setProcess(proc);
// Ensure activity is allowed to be resumed after process has set.
@@ -835,8 +835,6 @@
final IActivityClientController activityClientController =
proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController;
r.launchCount++;
- r.lastLaunchTime = SystemClock.uptimeMillis();
- proc.setLastActivityLaunchTime(r.lastLaunchTime);
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 95169db..55d6b2f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -375,6 +375,9 @@
final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null;
int redoLayout = notifyAppTransitionStartingLocked(
+ AppTransition.isKeyguardGoingAwayTransitOld(transit),
+ AppTransition.isKeyguardOccludeTransitOld(transit),
+ topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
topOpeningAnim != null
? topOpeningAnim.getStatusBarTransitionsStartTime()
: SystemClock.uptimeMillis(),
@@ -413,11 +416,8 @@
}
void freeze() {
- final boolean keyguardGoingAwayCancelled = mNextAppTransitionRequests.contains(
+ final boolean keyguardGoingAway = mNextAppTransitionRequests.contains(
TRANSIT_KEYGUARD_GOING_AWAY);
- final boolean keyguardOccludedCancelled =
- mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_OCCLUDE)
- || mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_UNOCCLUDE);
// The RemoteAnimationControl didn't register AppTransitionListener and
// only initialized the finish and timeout callback when goodToGo().
@@ -429,7 +429,7 @@
mNextAppTransitionRequests.clear();
clear();
setReady();
- notifyAppTransitionCancelledLocked(keyguardGoingAwayCancelled, keyguardOccludedCancelled);
+ notifyAppTransitionCancelledLocked(keyguardGoingAway);
}
private void setAppTransitionState(int state) {
@@ -479,11 +479,9 @@
}
}
- private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
+ private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAway) {
for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAwayCancelled,
- keyguardOccludedCancelled);
+ mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAway);
}
}
@@ -493,12 +491,14 @@
}
}
- private int notifyAppTransitionStartingLocked(long statusBarAnimationStartTime,
+ private int notifyAppTransitionStartingLocked(boolean keyguardGoingAway,
+ boolean keyguardOcclude, long duration, long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
int redoLayout = 0;
for (int i = 0; i < mListeners.size(); i++) {
- redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(
- statusBarAnimationStartTime, statusBarAnimationDuration);
+ redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway,
+ keyguardOcclude, duration, statusBarAnimationStartTime,
+ statusBarAnimationDuration);
}
return redoLayout;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index a645e89..44f388b 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -20,6 +20,10 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
@@ -77,9 +81,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Rect;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
@@ -89,6 +95,7 @@
import android.view.WindowManager.TransitionFlags;
import android.view.WindowManager.TransitionOldType;
import android.view.WindowManager.TransitionType;
+import android.view.animation.Animation;
import android.window.ITaskFragmentOrganizer;
import com.android.internal.annotations.VisibleForTesting;
@@ -290,6 +297,7 @@
final int flags = appTransition.getTransitFlags();
layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
+ handleNonAppWindowsInTransition(transit, flags);
appTransition.postAnimationCallback();
appTransition.clear();
} finally {
@@ -1031,6 +1039,32 @@
return;
}
+ if (AppTransition.isActivityTransitOld(transit)) {
+ final ArrayList<Pair<ActivityRecord, Rect>> closingLetterboxes = new ArrayList();
+ for (int i = 0; i < closingApps.size(); ++i) {
+ ActivityRecord closingApp = closingApps.valueAt(i);
+ if (closingApp.areBoundsLetterboxed()) {
+ final Rect insets = closingApp.getLetterboxInsets();
+ closingLetterboxes.add(new Pair(closingApp, insets));
+ }
+ }
+
+ for (int i = 0; i < openingApps.size(); ++i) {
+ ActivityRecord openingApp = openingApps.valueAt(i);
+ if (openingApp.areBoundsLetterboxed()) {
+ final Rect openingInsets = openingApp.getLetterboxInsets();
+ for (Pair<ActivityRecord, Rect> closingLetterbox : closingLetterboxes) {
+ final Rect closingInsets = closingLetterbox.second;
+ if (openingInsets.equals(closingInsets)) {
+ ActivityRecord closingApp = closingLetterbox.first;
+ openingApp.setNeedsLetterboxedAnimation(true);
+ closingApp.setNeedsLetterboxedAnimation(true);
+ }
+ }
+ }
+ }
+ }
+
final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
openingApps, closingApps, true /* visible */);
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
@@ -1137,6 +1171,30 @@
}
}
+ private void handleNonAppWindowsInTransition(@TransitionOldType int transit, int flags) {
+ if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+ && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
+ if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
+ Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+ if (anim != null) {
+ anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
+ mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
+ }
+ }
+ }
+ if ((transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+ || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER)
+ && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
+ mDisplayContent.startKeyguardExitOnNonAppWindows(
+ transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
+ }
+ }
+
private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps,
ArrayMap<WindowContainer, Integer> outReasons) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0422906..b033dca 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -504,6 +504,7 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ mTransitionController.collectForDisplayAreaChange(this);
mTmpConfiguration.setTo(getConfiguration());
super.onConfigurationChanged(newParentConfig);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 721497e..8a34af3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5946,6 +5946,9 @@
if (changes != 0) {
Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ mTempConfig + " for displayId=" + mDisplayId);
+ if (isReady() && mTransitionController.isShellTransitionsEnabled()) {
+ requestChangeTransitionIfNeeded(changes, null /* displayChange */);
+ }
onRequestedOverrideConfigurationChanged(mTempConfig);
final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
@@ -5962,9 +5965,6 @@
}
mWmService.mDisplayNotificationController.dispatchDisplayChanged(
this, getConfiguration());
- if (isReady() && mTransitionController.isShellTransitionsEnabled()) {
- requestChangeTransitionIfNeeded(changes, null /* displayChange */);
- }
}
return changes;
}
@@ -6598,8 +6598,7 @@
}
@Override
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
// It is only needed when freezing display in legacy transition.
if (mTransitionController.isShellTransitionsEnabled()) return;
continueUpdateOrientationForDiffOrienLaunchingApp();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 24cef31..1a34c93 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -602,8 +602,9 @@
}
@Override
- public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
- long statusBarAnimationDuration) {
+ public int onAppTransitionStartingLocked(boolean keyguardGoingAway,
+ boolean keyguardOccluding, long duration,
+ long statusBarAnimationStartTime, long statusBarAnimationDuration) {
mHandler.post(() -> {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
if (statusBar != null) {
@@ -615,8 +616,7 @@
}
@Override
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
mHandler.post(mAppTransitionCancelled);
}
@@ -794,11 +794,11 @@
}
public void setAwake(boolean awake) {
- if (awake == mAwake) {
- return;
- }
- mAwake = awake;
- synchronized (mService.mGlobalLock) {
+ synchronized (mLock) {
+ if (awake == mAwake) {
+ return;
+ }
+ mAwake = awake;
if (!mDisplayContent.isDefaultDisplay) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 8dd5850..97609a7 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -513,19 +513,6 @@
return true;
}
- /**
- * Utility to get a rotating displaycontent from a Transition.
- * @return null if the transition doesn't contain a rotating display.
- */
- static DisplayContent getDisplayFromTransition(Transition transition) {
- for (int i = transition.mParticipants.size() - 1; i >= 0; --i) {
- final WindowContainer wc = transition.mParticipants.valueAt(i);
- if (!(wc instanceof DisplayContent)) continue;
- return (DisplayContent) wc;
- }
- return null;
- }
-
private void startRemoteRotation(int fromRotation, int toRotation) {
mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
fromRotation, toRotation, null /* newDisplayAreaInfo */,
@@ -545,11 +532,6 @@
throw new IllegalStateException("Trying to rotate outside a transition");
}
mDisplayContent.mTransitionController.collect(mDisplayContent);
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
- // handling is synchronized.
- mDisplayContent.mTransitionController.collectForDisplayAreaChange(mDisplayContent,
- null /* use collecting transition */);
}
mService.mAtmService.deferWindowLayout();
try {
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index df3109a..27550d9 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -56,6 +56,7 @@
private final Supplier<Boolean> mHasWallpaperBackgroundSupplier;
private final Supplier<Integer> mBlurRadiusSupplier;
private final Supplier<Float> mDarkScrimAlphaSupplier;
+ private final Supplier<SurfaceControl> mParentSurfaceSupplier;
private final Rect mOuter = new Rect();
private final Rect mInner = new Rect();
@@ -87,7 +88,8 @@
Supplier<Integer> blurRadiusSupplier,
Supplier<Float> darkScrimAlphaSupplier,
IntConsumer doubleTapCallbackX,
- IntConsumer doubleTapCallbackY) {
+ IntConsumer doubleTapCallbackY,
+ Supplier<SurfaceControl> parentSurface) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mAreCornersRounded = areCornersRounded;
@@ -97,6 +99,7 @@
mDarkScrimAlphaSupplier = darkScrimAlphaSupplier;
mDoubleTapCallbackX = doubleTapCallbackX;
mDoubleTapCallbackY = doubleTapCallbackY;
+ mParentSurfaceSupplier = parentSurface;
}
/**
@@ -121,7 +124,6 @@
mFullWindowSurface.layout(outer.left, outer.top, outer.right, outer.bottom, surfaceOrigin);
}
-
/**
* Gets the insets between the outer and inner rects.
*/
@@ -333,6 +335,7 @@
private SurfaceControl mSurface;
private Color mColor;
private boolean mHasWallpaperBackground;
+ private SurfaceControl mParentSurface;
private final Rect mSurfaceFrameRelative = new Rect();
private final Rect mLayoutFrameGlobal = new Rect();
@@ -403,10 +406,12 @@
}
mColor = mColorSupplier.get();
+ mParentSurface = mParentSurfaceSupplier.get();
t.setColor(mSurface, getRgbColorArray());
t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
mSurfaceFrameRelative.height());
+ t.reparent(mSurface, mParentSurface);
mHasWallpaperBackground = mHasWallpaperBackgroundSupplier.get();
updateAlphaAndBlur(t);
@@ -452,12 +457,13 @@
public boolean needsApplySurfaceChanges() {
return !mSurfaceFrameRelative.equals(mLayoutFrameRelative)
- // If mSurfaceFrameRelative is empty then mHasWallpaperBackground and mColor
- // may never be updated in applySurfaceChanges but this doesn't mean that
- // update is needed.
+ // If mSurfaceFrameRelative is empty then mHasWallpaperBackground, mColor,
+ // and mParentSurface may never be updated in applySurfaceChanges but this
+ // doesn't mean that update is needed.
|| !mSurfaceFrameRelative.isEmpty()
&& (mHasWallpaperBackgroundSupplier.get() != mHasWallpaperBackground
- || !mColorSupplier.get().equals(mColor));
+ || !mColorSupplier.get().equals(mColor)
+ || mParentSurfaceSupplier.get() != mParentSurface);
}
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 57c60f4..a469c6b 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -265,7 +265,7 @@
}
/**
- * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+ * Overrides corners radius for activities presented in the letterbox mode. If given value < 0,
* both it and a value of {@link
* com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
* corners of the activity won't be rounded.
@@ -275,7 +275,7 @@
}
/**
- * Resets corners raidus for activities presented in the letterbox mode to {@link
+ * Resets corners radius for activities presented in the letterbox mode to {@link
* com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
*/
void resetLetterboxActivityCornersRadius() {
@@ -291,7 +291,7 @@
}
/**
- * Gets corners raidus for activities presented in the letterbox mode.
+ * Gets corners radius for activities presented in the letterbox mode.
*/
int getLetterboxActivityCornersRadius() {
return mLetterboxActivityCornersRadius;
@@ -318,7 +318,7 @@
/**
* Sets color of letterbox background which is used when {@link
* #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
+ * fallback for other background types.
*/
void setLetterboxBackgroundColor(Color color) {
mLetterboxBackgroundColorOverride = color;
@@ -327,7 +327,7 @@
/**
* Sets color ID of letterbox background which is used when {@link
* #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
+ * fallback for other background types.
*/
void setLetterboxBackgroundColorResourceId(int colorId) {
mLetterboxBackgroundColorResourceIdOverride = colorId;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index c8ed602..317c93e 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -89,7 +89,7 @@
// Taskbar expanded height. Used to determine whether to crop an app window to display rounded
// corners above the taskbar.
- private float mExpandedTaskBarHeight;
+ private final float mExpandedTaskBarHeight;
private boolean mShowWallpaperForLetterboxBackground;
@@ -120,7 +120,7 @@
}
}
- boolean hasWallpaperBackgroudForLetterbox() {
+ boolean hasWallpaperBackgroundForLetterbox() {
return mShowWallpaperForLetterboxBackground;
}
@@ -137,6 +137,11 @@
void getLetterboxInnerBounds(Rect outBounds) {
if (mLetterbox != null) {
outBounds.set(mLetterbox.getInnerFrame());
+ final WindowState w = mActivityRecord.findMainWindow();
+ if (w == null) {
+ return;
+ }
+ adjustBoundsForTaskbar(w, outBounds);
} else {
outBounds.setEmpty();
}
@@ -160,13 +165,17 @@
}
void updateLetterboxSurface(WindowState winHint) {
+ updateLetterboxSurface(winHint, mActivityRecord.getSyncTransaction());
+ }
+
+ void updateLetterboxSurface(WindowState winHint, Transaction t) {
final WindowState w = mActivityRecord.findMainWindow();
if (w != winHint && winHint != null && w != null) {
return;
}
layoutLetterbox(winHint);
if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
- mLetterbox.applySurfaceChanges(mActivityRecord.getSyncTransaction());
+ mLetterbox.applySurfaceChanges(t);
}
}
@@ -191,14 +200,22 @@
mActivityRecord.mWmService.mTransactionFactory,
this::shouldLetterboxHaveRoundedCorners,
this::getLetterboxBackgroundColor,
- this::hasWallpaperBackgroudForLetterbox,
+ this::hasWallpaperBackgroundForLetterbox,
this::getLetterboxWallpaperBlurRadius,
this::getLetterboxWallpaperDarkScrimAlpha,
this::handleHorizontalDoubleTap,
- this::handleVerticalDoubleTap);
+ this::handleVerticalDoubleTap,
+ this::getLetterboxParentSurface);
mLetterbox.attachInput(w);
}
- mActivityRecord.getPosition(mTmpPoint);
+
+ if (mActivityRecord.isInLetterboxAnimation()) {
+ // In this case we attach the letterbox to the task instead of the activity.
+ mActivityRecord.getTask().getPosition(mTmpPoint);
+ } else {
+ mActivityRecord.getPosition(mTmpPoint);
+ }
+
// Get the bounds of the "space-to-fill". The transformed bounds have the highest
// priority because the activity is launched in a rotated environment. In multi-window
// mode, the task-level represents this. In fullscreen-mode, the task container does
@@ -215,6 +232,13 @@
}
}
+ SurfaceControl getLetterboxParentSurface() {
+ if (mActivityRecord.isInLetterboxAnimation()) {
+ return mActivityRecord.getTask().getSurfaceControl();
+ }
+ return mActivityRecord.getSurfaceControl();
+ }
+
private boolean shouldLetterboxHaveRoundedCorners() {
// TODO(b/214030873): remove once background is drawn for transparent activities
// Letterbox shouldn't have rounded corners if the activity is transparent
@@ -436,7 +460,7 @@
}
break;
case LETTERBOX_BACKGROUND_WALLPAPER:
- if (hasWallpaperBackgroudForLetterbox()) {
+ if (hasWallpaperBackgroundForLetterbox()) {
// Color is used for translucent scrim that dims wallpaper.
return Color.valueOf(Color.BLACK);
}
@@ -459,15 +483,14 @@
private void updateRoundedCorners(WindowState mainWindow) {
final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
if (windowSurface != null && windowSurface.isValid()) {
- Transaction transaction = mActivityRecord.getSyncTransaction();
+ final Transaction transaction = mActivityRecord.getSyncTransaction();
- final InsetsState insetsState = mainWindow.getInsetsState();
- final InsetsSource taskbarInsetsSource =
- insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
-
- if (!isLetterboxedNotForDisplayCutout(mainWindow)
- || !mLetterboxConfiguration.isLetterboxActivityCornersRounded()
- || taskbarInsetsSource == null) {
+ if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+ // We don't want corner radius on the window.
+ // In the case the ActivityRecord requires a letterboxed animation we never want
+ // rounded corners on the window because rounded corners are applied at the
+ // animation-bounds surface level and rounded corners on the window would interfere
+ // with that leading to unexpected rounded corner positioning during the animation.
transaction
.setWindowCrop(windowSurface, null)
.setCornerRadius(windowSurface, 0);
@@ -476,48 +499,89 @@
Rect cropBounds = null;
- // Rounded corners should be displayed above the taskbar. When taskbar is hidden,
- // an insets frame is equal to a navigation bar which shouldn't affect position of
- // rounded corners since apps are expected to handle navigation bar inset.
- // This condition checks whether the taskbar is visible.
- // Do not crop the taskbar inset if the window is in immersive mode - the user can
- // swipe to show/hide the taskbar as an overlay.
- if (taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight
- && taskbarInsetsSource.isVisible()) {
+ if (hasVisibleTaskbar(mainWindow)) {
cropBounds = new Rect(mActivityRecord.getBounds());
// Activity bounds are in screen coordinates while (0,0) for activity's surface
// control is at the top left corner of an app window so offsetting bounds
// accordingly.
cropBounds.offsetTo(0, 0);
- // Rounded cornerners should be displayed above the taskbar.
- cropBounds.bottom =
- Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top);
- if (mActivityRecord.inSizeCompatMode()
- && mActivityRecord.getSizeCompatScale() < 1.0f) {
- cropBounds.scale(1.0f / mActivityRecord.getSizeCompatScale());
- }
+ // Rounded corners should be displayed above the taskbar.
+ adjustBoundsForTaskbarUnchecked(mainWindow, cropBounds);
}
transaction
.setWindowCrop(windowSurface, cropBounds)
- .setCornerRadius(windowSurface, getRoundedCorners(insetsState));
+ .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow));
}
}
- // Returns rounded corners radius based on override in
+ private boolean requiresRoundedCorners(WindowState mainWindow) {
+ final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
+
+ return isLetterboxedNotForDisplayCutout(mainWindow)
+ && mLetterboxConfiguration.isLetterboxActivityCornersRounded()
+ && taskbarInsetsSource != null;
+ }
+
+ // Returns rounded corners radius the letterboxed activity should have based on override in
// R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii.
// Device corners can be different on the right and left sides but we use the same radius
// for all corners for consistency and pick a minimal bottom one for consistency with a
// taskbar rounded corners.
- private int getRoundedCorners(InsetsState insetsState) {
+ int getRoundedCornersRadius(WindowState mainWindow) {
+ if (!requiresRoundedCorners(mainWindow)) {
+ return 0;
+ }
+
if (mLetterboxConfiguration.getLetterboxActivityCornersRadius() >= 0) {
return mLetterboxConfiguration.getLetterboxActivityCornersRadius();
}
+
+ final InsetsState insetsState = mainWindow.getInsetsState();
return Math.min(
getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT),
getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT));
}
+ /**
+ * Returns whether the taskbar is visible. Returns false if the window is in immersive mode,
+ * since the user can swipe to show/hide the taskbar as an overlay.
+ */
+ private boolean hasVisibleTaskbar(WindowState mainWindow) {
+ final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
+
+ return taskbarInsetsSource != null
+ && taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight
+ && taskbarInsetsSource.isVisible();
+ }
+
+ private InsetsSource getTaskbarInsetsSource(WindowState mainWindow) {
+ final InsetsState insetsState = mainWindow.getInsetsState();
+ return insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ }
+
+ private void adjustBoundsForTaskbar(WindowState mainWindow, Rect bounds) {
+ // Rounded corners should be displayed above the taskbar. When taskbar is hidden,
+ // an insets frame is equal to a navigation bar which shouldn't affect position of
+ // rounded corners since apps are expected to handle navigation bar inset.
+ // This condition checks whether the taskbar is visible.
+ // Do not crop the taskbar inset if the window is in immersive mode - the user can
+ // swipe to show/hide the taskbar as an overlay.
+ if (hasVisibleTaskbar(mainWindow)) {
+ adjustBoundsForTaskbarUnchecked(mainWindow, bounds);
+ }
+ }
+
+ private void adjustBoundsForTaskbarUnchecked(WindowState mainWindow, Rect bounds) {
+ // Rounded corners should be displayed above the taskbar.
+ bounds.bottom =
+ Math.min(bounds.bottom, getTaskbarInsetsSource(mainWindow).getFrame().top);
+ if (mActivityRecord.inSizeCompatMode()
+ && mActivityRecord.getSizeCompatScale() < 1.0f) {
+ bounds.scale(1.0f / mActivityRecord.getSizeCompatScale());
+ }
+ }
+
private int getInsetsStateCornerRadius(
InsetsState insetsState, @RoundedCorner.Position int position) {
RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position);
@@ -592,7 +656,7 @@
+ letterboxBackgroundTypeToString(
mLetterboxConfiguration.getLetterboxBackgroundType()));
pw.println(prefix + " letterboxCornerRadius="
- + getRoundedCorners(mainWin.getInsetsState()));
+ + getRoundedCornersRadius(mainWin));
if (mLetterboxConfiguration.getLetterboxBackgroundType()
== LETTERBOX_BACKGROUND_WALLPAPER) {
pw.println(prefix + " isLetterboxWallpaperBlurSupported="
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 64749cf..a89894d 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -101,7 +101,6 @@
if (t != null) {
mDisplayContent.mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
- mTransitionController.collectForDisplayAreaChange(mDisplayContent, t);
mTransition = t;
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index db79eae..5b702ea 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -161,15 +161,15 @@
*/
final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
@Override
- public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
+ public int onAppTransitionStartingLocked(boolean keyguardGoingAway,
+ boolean keyguardOccluding, long duration, long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
continueDeferredCancel();
return 0;
}
@Override
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
continueDeferredCancel();
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index c7f8a1e..f3670e4 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -27,7 +27,10 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.power.Boost;
@@ -374,43 +377,45 @@
final int targetSurfaceWidth = bounds.width();
if (maxExtensionInsets.left < 0) {
- final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.top, bounds.left + 1,
+ bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
-maxExtensionInsets.left, targetSurfaceHeight);
- final int xPos = maxExtensionInsets.left;
- final int yPos = 0;
+ final int xPos = bounds.left + maxExtensionInsets.left;
+ final int yPos = bounds.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Left Edge Extension", transaction);
}
if (maxExtensionInsets.top < 0) {
- final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.top, targetSurfaceWidth,
+ bounds.top + 1);
final Rect extensionRect = new Rect(0, 0,
targetSurfaceWidth, -maxExtensionInsets.top);
- final int xPos = 0;
- final int yPos = maxExtensionInsets.top;
+ final int xPos = bounds.left;
+ final int yPos = bounds.top + maxExtensionInsets.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Top Edge Extension", transaction);
}
if (maxExtensionInsets.right < 0) {
- final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0,
- targetSurfaceWidth, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.right - 1, bounds.top, bounds.right,
+ bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
-maxExtensionInsets.right, targetSurfaceHeight);
- final int xPos = targetSurfaceWidth;
- final int yPos = 0;
+ final int xPos = bounds.right;
+ final int yPos = bounds.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Right Edge Extension", transaction);
}
if (maxExtensionInsets.bottom < 0) {
- final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1,
- targetSurfaceWidth, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.bottom - 1,
+ bounds.right, bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
targetSurfaceWidth, -maxExtensionInsets.bottom);
- final int xPos = maxExtensionInsets.left;
- final int yPos = targetSurfaceHeight;
+ final int xPos = bounds.left;
+ final int yPos = bounds.bottom;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Bottom Edge Extension", transaction);
}
@@ -453,16 +458,20 @@
.setHidden(true)
.setCallsite("DefaultTransitionHandler#startAnimation")
.setOpaque(true)
- .setBufferSize(edgeBounds.width(), edgeBounds.height())
+ .setBufferSize(extensionRect.width(), extensionRect.height())
.build();
- final Surface surface = new Surface(edgeExtensionLayer);
- surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
- edgeBuffer.getColorSpace());
- surface.release();
+ BitmapShader shader = new BitmapShader(edgeBuffer.asBitmap(),
+ android.graphics.Shader.TileMode.CLAMP,
+ android.graphics.Shader.TileMode.CLAMP);
+ final Paint paint = new Paint();
+ paint.setShader(shader);
- final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
- final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);
+ final Surface surface = new Surface(edgeExtensionLayer);
+ Canvas c = surface.lockHardwareCanvas();
+ c.drawRect(extensionRect, paint);
+ surface.unlockCanvasAndPost(c);
+ surface.release();
synchronized (mEdgeExtensionLock) {
if (!mEdgeExtensions.containsKey(leash)) {
@@ -472,7 +481,6 @@
return;
}
- startTransaction.setScale(edgeExtensionLayer, scaleX, scaleY);
startTransaction.reparent(edgeExtensionLayer, leash);
startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
@@ -508,8 +516,6 @@
throw new RuntimeException("Unexpected edgeBounds and extensionRect heights");
}
-
-
private static final class RunningAnimation {
final AnimationSpec mAnimSpec;
final SurfaceControl mLeash;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 3a17e48..803890b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -31,7 +31,13 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -66,6 +72,7 @@
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -73,6 +80,7 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.view.animation.Animation;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
@@ -1058,9 +1066,36 @@
private void handleNonAppWindowsInTransition(@NonNull DisplayContent dc,
@TransitionType int transit, @TransitionFlags int flags) {
+ if ((transit == TRANSIT_KEYGUARD_GOING_AWAY
+ || (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0)
+ && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
+ if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
+ Animation anim = mController.mAtm.mWindowManager.mPolicy
+ .createKeyguardWallpaperExit(
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+ if (anim != null) {
+ anim.scaleCurrentDuration(
+ mController.mAtm.mWindowManager.getTransitionAnimationScaleLocked());
+ dc.mWallpaperController.startWallpaperAnimation(anim);
+ }
+ }
+ dc.startKeyguardExitOnNonAppWindows(
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
+ if (!WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation) {
+ // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI
+ // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't
+ // need to call IKeyguardService#keyguardGoingAway here.
+ mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(
+ SystemClock.uptimeMillis(), 0 /* duration */);
+ }
+ }
if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange(
- false /* notify */);
+ true /* keyguardOccludingStarted */);
}
}
@@ -1606,6 +1641,19 @@
return mainWin.getAttrs().rotationAnimation;
}
+ /** Applies the new configuration and returns {@code true} if there is a display change. */
+ boolean applyDisplayChangeIfNeeded() {
+ boolean changed = false;
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final WindowContainer<?> wc = mParticipants.valueAt(i);
+ final DisplayContent dc = wc.asDisplayContent();
+ if (dc == null || !mChanges.get(dc).hasChanged(dc)) continue;
+ dc.sendNewConfiguration();
+ changed = true;
+ }
+ return changed;
+ }
+
boolean getLegacyIsReady() {
return isCollecting() && mSyncId >= 0;
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 79dfaa9..846aa3e 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -463,13 +463,12 @@
}
/**
- * Collects the window containers which need to be synced with the changing display (e.g.
- * rotating) to the given transition or the current collecting transition.
+ * Collects the window containers which need to be synced with the changing display area into
+ * the current collecting transition.
*/
- void collectForDisplayAreaChange(@NonNull DisplayArea<?> wc, @Nullable Transition incoming) {
- if (incoming == null) incoming = mCollectingTransition;
- if (incoming == null) return;
- final Transition transition = incoming;
+ void collectForDisplayAreaChange(@NonNull DisplayArea<?> wc) {
+ final Transition transition = mCollectingTransition;
+ if (transition == null || !transition.mParticipants.contains(wc)) return;
// Collect all visible tasks.
wc.forAllLeafTasks(task -> {
if (task.isVisible()) {
@@ -638,9 +637,11 @@
}
void dispatchLegacyAppTransitionStarting(TransitionInfo info, long statusBarTransitionDelay) {
+ final boolean keyguardGoingAway = info.isKeyguardGoingAway();
for (int i = 0; i < mLegacyListeners.size(); ++i) {
// TODO(shell-transitions): handle (un)occlude transition.
- mLegacyListeners.get(i).onAppTransitionStartingLocked(
+ mLegacyListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway,
+ false /* keyguardOcclude */, 0 /* durationHint */,
SystemClock.uptimeMillis() + statusBarTransitionDelay,
AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
}
@@ -655,7 +656,7 @@
void dispatchLegacyAppTransitionCancelled() {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
mLegacyListeners.get(i).onAppTransitionCancelledLocked(
- false /* keyguardGoingAwayCancelled */, false /* keyguardOccludedCancelled */);
+ false /* keyguardGoingAway */);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 70dd9f3..73658b2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3019,6 +3019,10 @@
final float windowCornerRadius = !inMultiWindowMode()
? getDisplayContent().getWindowCornerRadius()
: 0;
+ if (asActivityRecord() != null
+ && asActivityRecord().isNeedsLetterboxedAnimation()) {
+ asActivityRecord().getLetterboxInnerBounds(mTmpRect);
+ }
AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
getDisplayContent().mAppTransition.canSkipFirstFrame(),
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 4b5b6da..a71c386 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -220,13 +220,9 @@
/**
* Called when a pending app transition gets cancelled.
*
- * @param keyguardGoingAwayCancelled {@code true} if keyguard going away transition was
- * cancelled.
- * @param keyguardOccludedCancelled {@code true} if keyguard (un)occluded transition was
- * cancelled.
+ * @param keyguardGoingAway true if keyguard going away transition got cancelled.
*/
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {}
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {}
/**
* Called when an app transition is timed out.
@@ -236,6 +232,9 @@
/**
* Called when an app transition gets started
*
+ * @param keyguardGoingAway true if keyguard going away transition is started.
+ * @param keyguardOccluding true if keyguard (un)occlude transition is started.
+ * @param duration the total duration of the transition
* @param statusBarAnimationStartTime the desired start time for all visual animations in
* the status bar caused by this app transition in uptime millis
* @param statusBarAnimationDuration the duration for all visual animations in the status
@@ -246,7 +245,8 @@
* {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER},
* or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
*/
- public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
+ public int onAppTransitionStartingLocked(boolean keyguardGoingAway,
+ boolean keyguardOccluding, long duration, long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
return 0;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 298f93d..22411bb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -425,6 +425,32 @@
SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, false);
/**
+ * Run Keyguard animation as remote animation in System UI instead of local animation in
+ * the server process.
+ *
+ * 0: Runs all keyguard animation as local animation
+ * 1: Only runs keyguard going away animation as remote animation
+ * 2: Runs all keyguard animation as remote animation
+ */
+ private static final String ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY =
+ "persist.wm.enable_remote_keyguard_animation";
+
+ private static final int sEnableRemoteKeyguardAnimation =
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
+
+ /**
+ * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
+ */
+ public static final boolean sEnableRemoteKeyguardGoingAwayAnimation =
+ sEnableRemoteKeyguardAnimation >= 1;
+
+ /**
+ * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
+ */
+ public static final boolean sEnableRemoteKeyguardOccludeAnimation =
+ sEnableRemoteKeyguardAnimation >= 2;
+
+ /**
* Allows a fullscreen windowing mode activity to launch in its desired orientation directly
* when the display has different orientation.
*/
@@ -1092,8 +1118,7 @@
= new WindowManagerInternal.AppTransitionListener() {
@Override
- public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled,
- boolean keyguardOccludedCancelled) {
+ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3b9cd36..4f03264 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -397,17 +397,8 @@
mService.deferWindowLayout();
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
try {
- if (transition != null) {
- // First check if we have a display rotation transition and if so, update it.
- final DisplayContent dc = DisplayRotation.getDisplayFromTransition(transition);
- if (dc != null && transition.mChanges.get(dc).hasChanged(dc)) {
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once
- // wallpaper handling is synchronized.
- dc.mTransitionController.collectForDisplayAreaChange(dc, transition);
- dc.sendNewConfiguration();
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
+ if (transition != null && transition.applyDisplayChangeIfNeeded()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
final int hopSize = hops.size();
@@ -428,15 +419,6 @@
addToSyncSet(syncId, wc);
}
if (transition != null) transition.collect(wc);
- final DisplayArea da = wc.asDisplayArea();
- // Only check DisplayArea here as a similar thing is done for DisplayContent above.
- if (da != null && wc.asDisplayContent() == null
- && entry.getValue().getWindowingMode() != da.getWindowingMode()) {
- // Go through all tasks and collect them before changing the windowing mode of a
- // display-level container.
- // TODO(shell-transitions): handle this more elegantly.
- da.mTransitionController.collectForDisplayAreaChange(da, transition);
- }
if ((entry.getValue().getChangeMask()
& WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a85dcbf..d2b9bda 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -6041,7 +6041,7 @@
}
boolean hasWallpaperForLetterboxBackground() {
- return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
+ return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroundForLetterbox();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/input/OWNERS b/services/tests/servicestests/src/com/android/server/input/OWNERS
index d701f23..6e9aa1d 100644
--- a/services/tests/servicestests/src/com/android/server/input/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/input/OWNERS
@@ -1 +1,2 @@
-include /core/java/android/hardware/input/OWNERS
+include /services/core/java/com/android/server/input/OWNERS
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 34b40c7..b1ad8ec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -16,53 +16,79 @@
package com.android.server.pm;
+import static android.os.UserManager.DISALLOW_USER_SWITCH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.app.PropertyInvalidatedCache;
+import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Postsubmit;
import android.support.test.uiautomator.UiDevice;
-import android.test.AndroidTestCase;
-import android.text.TextUtils;
import android.util.AtomicFile;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
+/** Test {@link UserManagerService} functionality. */
@Postsubmit
-@SmallTest
-public class UserManagerServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class UserManagerServiceTest {
private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
private File restrictionsFile;
private int tempUserId = UserHandle.USER_NULL;
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private UserManagerService mUserManagerService;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setup() throws Exception {
+ // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+ // TODO: Remove once UMS supports proper dependency injection
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ // Disable binder caches in this process.
+ PropertyInvalidatedCache.disableForTestMode();
+
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+
restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml");
restrictionsFile.delete();
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void teardown() throws Exception {
restrictionsFile.delete();
if (tempUserId != UserHandle.USER_NULL) {
UserManager.get(mContext).removeUser(tempUserId);
}
- super.tearDown();
}
+ @Test
public void testWriteReadApplicationRestrictions() throws IOException {
AtomicFile atomicFile = new AtomicFile(restrictionsFile);
Bundle bundle = createBundle();
UserManagerService.writeApplicationRestrictionsLAr(bundle, atomicFile);
- assertTrue(atomicFile.getBaseFile().exists());
+ assertThat(atomicFile.getBaseFile().exists()).isTrue();
String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
System.out.println("restrictionsFile: " + s);
bundle = UserManagerService.readApplicationRestrictionsLAr(atomicFile);
@@ -70,22 +96,22 @@
assertBundle(bundle);
}
+ @Test
public void testAddUserWithAccount() {
UserManager um = UserManager.get(mContext);
UserInfo user = um.createUser("Test User", 0);
- assertNotNull(user);
+ assertThat(user).isNotNull();
tempUserId = user.id;
String accountName = "Test Account";
um.setUserAccount(tempUserId, accountName);
- assertEquals(accountName, um.getUserAccount(tempUserId));
+ assertThat(um.getUserAccount(tempUserId)).isEqualTo(accountName);
}
+ @Test
public void testUserSystemPackageWhitelist() throws Exception {
String cmd = "cmd user report-system-user-package-whitelist-problems --critical-only";
final String result = runShellCommand(cmd);
- if (!TextUtils.isEmpty(result)) {
- fail("Command '" + cmd + " reported errors:\n" + result);
- }
+ assertThat(result).isEmpty();
}
private Bundle createBundle() {
@@ -114,26 +140,141 @@
}
private void assertBundle(Bundle bundle) {
- assertFalse(bundle.getBoolean("boolean_0"));
- assertTrue(bundle.getBoolean("boolean_1"));
- assertEquals(100, bundle.getInt("integer"));
- assertEquals("", bundle.getString("empty"));
- assertEquals("text", bundle.getString("string"));
- assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]")));
+ assertThat(bundle.getBoolean("boolean_0")).isFalse();
+ assertThat(bundle.getBoolean("boolean_1")).isTrue();
+ assertThat(bundle.getInt("integer")).isEqualTo(100);
+ assertThat(bundle.getString("empty")).isEqualTo("");
+ assertThat(bundle.getString("string")).isEqualTo("text");
+ assertThat(Arrays.asList(bundle.getStringArray("string[]")))
+ .isEqualTo(Arrays.asList(STRING_ARRAY));
Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array");
- assertEquals(2, bundle_array.length);
+ assertThat(bundle_array.length).isEqualTo(2);
Bundle bundle1 = (Bundle) bundle_array[0];
- assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
- assertNotNull(bundle1.getBundle("bundle_array_bundle"));
+ assertThat(bundle1.getString("bundle_array_string"))
+ .isEqualTo("bundle_array_string");
+ assertThat(bundle1.getBundle("bundle_array_bundle")).isNotNull();
Bundle bundle2 = (Bundle) bundle_array[1];
- assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
+ assertThat(bundle2.getString("bundle_array_string2"))
+ .isEqualTo("bundle_array_string2");
Bundle childBundle = bundle.getBundle("bundle");
- assertEquals("bundle_string", childBundle.getString("bundle_string"));
- assertEquals(1, childBundle.getInt("bundle_int"));
+ assertThat(childBundle.getString("bundle_string"))
+ .isEqualTo("bundle_string");
+ assertThat(childBundle.getInt("bundle_int")).isEqualTo(1);
}
+ @Test
+ public void assertHasUserRestriction() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+
+ mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId);
+ assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isTrue();
+
+ mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
+ assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isFalse();
+ }
+
+ @Test
+ public void assertIsUserSwitcherEnabledOnMultiUserSettings() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ resetUserSwitcherEnabled();
+
+ setUserSwitch(false);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();
+
+ setUserSwitch(true);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
+ }
+
+ @Test
+ public void assertIsUserSwitcherEnabledOnMaxSupportedUsers() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ setMaxSupportedUsers(1);
+
+ assertThat(UserManager.supportsMultipleUsers()).isFalse();
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();
+
+ setMaxSupportedUsers(8);
+
+ assertThat(UserManager.supportsMultipleUsers()).isTrue();
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
+ }
+
+
+ @Test
+ public void assertIsUserSwitcherEnabledOnShowMultiuserUI() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ setShowMultiuserUI(false);
+
+ assertThat(UserManager.supportsMultipleUsers()).isFalse();
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();
+
+ setShowMultiuserUI(true);
+
+ assertThat(UserManager.supportsMultipleUsers()).isTrue();
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
+ }
+
+ @Test
+ public void assertIsUserSwitcherEnabledOnUserRestrictions() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ resetUserSwitcherEnabled();
+
+ mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();
+
+ mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
+ }
+
+ @Test
+ public void assertIsUserSwitcherEnabledOnDemoMode() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ resetUserSwitcherEnabled();
+
+ setDeviceDemoMode(true);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();
+
+ setDeviceDemoMode(false);
+ assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
+ }
+
+ private void resetUserSwitcherEnabled() throws Exception {
+ int userId = ActivityManager.getCurrentUser();
+ setUserSwitch(true);
+ setShowMultiuserUI(true);
+ setDeviceDemoMode(false);
+ setMaxSupportedUsers(8);
+ mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
+ }
+
+ private void setUserSwitch(boolean enabled) {
+ android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.USER_SWITCHER_ENABLED, enabled ? 1 : 0);
+ }
+
+ private void setDeviceDemoMode(boolean enabled) {
+ android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEVICE_DEMO_MODE, enabled ? 1 : 0);
+ }
+
+
private static String runShellCommand(String cmd) throws Exception {
return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.executeShellCommand(cmd);
}
+
+ private static String setSystemProperty(String name, String value) throws Exception {
+ final String oldValue = runShellCommand("getprop " + name);
+ assertThat(runShellCommand("setprop " + name + " " + value))
+ .isEqualTo("");
+ return oldValue;
+ }
+
+ private static void setMaxSupportedUsers(int max) throws Exception {
+ setSystemProperty("fw.max_users", String.valueOf(max));
+ }
+
+ public static void setShowMultiuserUI(boolean show) throws Exception {
+ setSystemProperty("fw.show_multiuserui", String.valueOf(show));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 40cda34..ec48e23 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4239,6 +4239,59 @@
}
@Test
+ public void testSubstituteAppName_hasPermission() throws RemoteException {
+ String subName = "Substitute Name";
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
+ .thenReturn(PERMISSION_GRANTED);
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .addExtras(extras);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testSubstituteAppNamePermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertTrue(posted.getNotification().extras
+ .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
+ assertEquals(posted.getNotification().extras
+ .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
+ }
+
+ @Test
+ public void testSubstituteAppName_noPermission() throws RemoteException {
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
+ .thenReturn(PERMISSION_DENIED);
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .addExtras(extras);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testSubstituteAppNamePermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertFalse(posted.getNotification().extras
+ .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
+ }
+
+ @Test
public void testGetNotificationCountLocked() {
String sampleTagToExclude = null;
int sampleIdToExclude = 0;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 598a22b..d62ac99 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -93,6 +93,7 @@
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.Parcel;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -2447,6 +2448,35 @@
}
@Test
+ public void testGetNotificationChannelGroup() throws Exception {
+ NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
+ NotificationChannel base =
+ new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+ base.setGroup("not");
+ NotificationChannel convo =
+ new NotificationChannel("convo", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+ convo.setGroup("not");
+ convo.setConversationId("not deleted", "banana");
+
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
+
+ NotificationChannelGroup g
+ = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
+ Parcel parcel = Parcel.obtain();
+ g.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup g2
+ = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
+ Parcel parcel2 = Parcel.obtain();
+ g2.writeToParcel(parcel2, 0);
+ parcel2.setDataPosition(0);
+ }
+
+ @Test
public void testOnUserRemoved() throws Exception {
int[] user0Uids = {98, 235, 16, 3782};
int[] user1Uids = new int[user0Uids.length];
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7a73f08..7244d94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1916,10 +1916,10 @@
testPlayer.start();
assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
assertNotNull(testPlayer.mLastReady);
- assertEquals(dc, DisplayRotation.getDisplayFromTransition(testPlayer.mLastTransit));
WindowContainerToken dcToken = dc.mRemoteToken.toWindowContainerToken();
assertNotEquals(testPlayer.mLastReady.getChange(dcToken).getEndRotation(),
testPlayer.mLastReady.getChange(dcToken).getStartRotation());
+ assertTrue(testPlayer.mLastTransit.applyDisplayChangeIfNeeded());
testPlayer.finish();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index e502f2f..d400a4c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -56,6 +56,7 @@
private boolean mHasWallpaperBackground = false;
private int mBlurRadius = 0;
private float mDarkScrimAlpha = 0.5f;
+ private SurfaceControl mParentSurface = mock(SurfaceControl.class);
@Before
public void setUp() throws Exception {
@@ -63,7 +64,8 @@
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
- /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {});
+ /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {},
+ () -> mParentSurface);
mTransaction = spy(StubTransaction.class);
}
@@ -205,6 +207,22 @@
}
@Test
+ public void testNeedsApplySurfaceChanges_setParentSurface() {
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
+ assertFalse(mLetterbox.needsApplySurfaceChanges());
+
+ mParentSurface = mock(SurfaceControl.class);
+
+ assertTrue(mLetterbox.needsApplySurfaceChanges());
+
+ mLetterbox.applySurfaceChanges(mTransaction);
+ verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
+ }
+
+ @Test
public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
mLetterbox.applySurfaceChanges(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 88e58ea..8546763 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -281,7 +281,7 @@
verify(mMockRunner).onAnimationCanceled(null /* taskIds */, null /* taskSnapshots */);
// Simulate the app transition finishing
- mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0);
+ mController.mAppTransitionListener.onAppTransitionStartingLocked(false, false, 0, 0, 0);
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 13da154..d2cb7ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -310,11 +310,11 @@
}
@Override
- public void startKeyguardExitAnimation(long startTime) {
+ public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
}
@Override
- public int applyKeyguardOcclusionChange(boolean notify) {
+ public int applyKeyguardOcclusionChange(boolean keyguardOccludingStarted) {
return 0;
}
diff --git a/tests/FlickerTests/libs/window-extensions-release.aar b/tests/FlickerTests/libs/window-extensions-release.aar
index 6fc9a67..918e514 100644
--- a/tests/FlickerTests/libs/window-extensions-release.aar
+++ b/tests/FlickerTests/libs/window-extensions-release.aar
Binary files differ
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
index 3b201f9..e4add80 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -16,6 +16,9 @@
package android.net.vcn.persistablebundleutils;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.isIkeOptionValid;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.telephony.TelephonyManager.APPTYPE_USIM;
@@ -134,15 +137,37 @@
verifyPersistableBundleEncodeDecodeIsLossless(params);
}
+ private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception {
+ final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+
+ final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+ final int subId = 1;
+ final EapSessionConfig eapConfig =
+ new EapSessionConfig.Builder()
+ .setEapIdentity(eapId)
+ .setEapSimConfig(subId, APPTYPE_USIM)
+ .setEapAkaConfig(subId, APPTYPE_USIM)
+ .build();
+ return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig);
+ }
+
@Test
public void testEncodeDecodeParamsWithIkeOptions() throws Exception {
- final IkeSessionParams params =
- createBuilderMinimum()
+ final IkeSessionParams.Builder builder =
+ createBuilderMinimumWithEap()
.addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH)
.addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500)
.addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT)
- .build();
- verifyPersistableBundleEncodeDecodeIsLossless(params);
+ .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY);
+ if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)) {
+ builder.addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION);
+ }
+ if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) {
+ builder.addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES);
+ }
+ verifyPersistableBundleEncodeDecodeIsLossless(builder.build());
}
private static InputStream openAssetsFile(String fileName) throws Exception {
@@ -176,19 +201,7 @@
@Test
public void testEncodeRecodeParamsWithEapAuth() throws Exception {
- final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
-
- final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
- final int subId = 1;
- final EapSessionConfig eapConfig =
- new EapSessionConfig.Builder()
- .setEapIdentity(eapId)
- .setEapSimConfig(subId, APPTYPE_USIM)
- .setEapAkaConfig(subId, APPTYPE_USIM)
- .build();
-
- final IkeSessionParams params =
- createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build();
+ final IkeSessionParams params = createBuilderMinimumWithEap().build();
verifyPersistableBundleEncodeDecodeIsLossless(params);
}
}