Merge "Make TestableFlagResolver part of the 'testables' lib."
diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
index a2aeb31..67b33e5 100644
--- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
@@ -17,6 +17,7 @@
package android.view;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
import android.content.Context;
import android.perftests.utils.PerfTestActivity;
@@ -72,6 +73,15 @@
@Test
public void testPerformHapticFeedback() throws Throwable {
+ // performHapticFeedback is now asynchronous, so should be very fast. This benchmark
+ // is primarily a regression test for the re-introduction of blocking calls in the path.
+
+ // Can't run back-to-back performHapticFeedback, as it will just enqueue on the oneway
+ // thread and fill up that buffer. Instead, we invoke at a speed of a fairly high frame
+ // rate - and this is still too fast to fully vibrate in reality, but should be able to
+ // clear queues.
+ int waitPerCallMillis = 5;
+
final BenchmarkState state = mBenchmarkRule.getState();
mActivityRule.runOnUiThread(() -> {
state.pauseTiming();
@@ -85,9 +95,17 @@
int flags = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
| HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
- while (state.keepRunning()) {
- assertTrue("Call to performHapticFeedback was ignored",
- view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, flags));
+ try {
+ while (state.keepRunning()) {
+ assertTrue("Call to performHapticFeedback was ignored",
+ view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS,
+ flags));
+ state.pauseTiming();
+ Thread.sleep(waitPerCallMillis);
+ state.resumeTiming();
+ }
+ } catch (InterruptedException e) {
+ fail("Unexpectedly interrupted");
}
});
}
diff --git a/api/Android.bp b/api/Android.bp
index 318748e..f49e6dd 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -100,7 +100,7 @@
"framework-connectivity-t",
"framework-devicelock",
"framework-graphics",
- "framework-healthconnect",
+ "framework-healthfitness",
"framework-media",
"framework-mediaprovider",
"framework-ondevicepersonalization",
@@ -119,7 +119,7 @@
system_server_classpath: [
"service-art",
"service-configinfrastructure",
- "service-healthconnect",
+ "service-healthfitness",
"service-media-s",
"service-permission",
"service-rkp",
diff --git a/boot/Android.bp b/boot/Android.bp
index d4a6500..83a46c5 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -88,8 +88,8 @@
module: "com.android.devicelock-bootclasspath-fragment",
},
{
- apex: "com.android.healthconnect",
- module: "com.android.healthconnect-bootclasspath-fragment",
+ apex: "com.android.healthfitness",
+ module: "com.android.healthfitness-bootclasspath-fragment",
},
{
apex: "com.android.i18n",
diff --git a/core/api/current.txt b/core/api/current.txt
index a57499b..d54290b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4319,6 +4319,7 @@
@UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
ctor public Activity();
method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public void clearOverrideActivityTransition(int);
method public void closeContextMenu();
method public void closeOptionsMenu();
method public android.app.PendingIntent createPendingResult(int, @NonNull android.content.Intent, int);
@@ -4487,6 +4488,8 @@
method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
method public void openContextMenu(android.view.View);
method public void openOptionsMenu();
+ method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int);
+ method public void overrideActivityTransition(int, @AnimRes int, @AnimRes int, @ColorInt int);
method public void overridePendingTransition(int, int);
method public void overridePendingTransition(int, int, int);
method public void postponeEnterTransition();
@@ -4588,6 +4591,8 @@
field protected static final int[] FOCUSED_STATE_SET;
field public static final int FULLSCREEN_MODE_REQUEST_ENTER = 1; // 0x1
field public static final int FULLSCREEN_MODE_REQUEST_EXIT = 0; // 0x0
+ field public static final int OVERRIDE_TRANSITION_CLOSE = 1; // 0x1
+ field public static final int OVERRIDE_TRANSITION_OPEN = 0; // 0x0
field public static final int RESULT_CANCELED = 0; // 0x0
field public static final int RESULT_FIRST_USER = 1; // 0x1
field public static final int RESULT_OK = -1; // 0xffffffff
@@ -4614,6 +4619,7 @@
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public java.util.List<android.app.ApplicationStartInfo> getHistoricalProcessStartReasons(@IntRange(from=0) int);
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
@@ -4639,7 +4645,9 @@
method @RequiresPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) public void killBackgroundProcesses(String);
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
+ method public void removeApplicationStartInfoCompleteListener();
method @Deprecated public void restartPackage(String);
+ method public void setApplicationStartInfoCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.ActivityManager.ApplicationStartInfoCompleteListener);
method public void setProcessStateSummary(@Nullable byte[]);
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
@@ -4662,6 +4670,10 @@
method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle);
}
+ public static interface ActivityManager.ApplicationStartInfoCompleteListener {
+ method public void onApplicationStartInfoComplete(@NonNull android.app.ApplicationStartInfo);
+ }
+
public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
ctor public ActivityManager.MemoryInfo();
method public int describeContents();
@@ -5221,6 +5233,52 @@
field public static final int REASON_USER_STOPPED = 11; // 0xb
}
+ public final class ApplicationStartInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDefiningUid();
+ method @Nullable public android.content.Intent getIntent();
+ method public int getLaunchMode();
+ method public int getPackageUid();
+ method public int getPid();
+ method @NonNull public String getProcessName();
+ method public int getRealUid();
+ method public int getReason();
+ method public int getStartType();
+ method public int getStartupState();
+ method @NonNull public java.util.Map<java.lang.Integer,java.lang.Long> getStartupTimestamps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationStartInfo> CREATOR;
+ field public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2; // 0x2
+ field public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4; // 0x4
+ field public static final int LAUNCH_MODE_SINGLE_TASK = 3; // 0x3
+ field public static final int LAUNCH_MODE_SINGLE_TOP = 1; // 0x1
+ field public static final int LAUNCH_MODE_STANDARD = 0; // 0x0
+ field public static final int STARTUP_STATE_ERROR = 1; // 0x1
+ field public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2; // 0x2
+ field public static final int STARTUP_STATE_STARTED = 0; // 0x0
+ field public static final int START_REASON_ALARM = 0; // 0x0
+ field public static final int START_REASON_BACKUP = 1; // 0x1
+ field public static final int START_REASON_BOOT_COMPLETE = 2; // 0x2
+ field public static final int START_REASON_BROADCAST = 3; // 0x3
+ field public static final int START_REASON_CONTENT_PROVIDER = 4; // 0x4
+ field public static final int START_REASON_JOB = 5; // 0x5
+ field public static final int START_REASON_LAUNCHER = 6; // 0x6
+ field public static final int START_REASON_OTHER = 7; // 0x7
+ field public static final int START_REASON_PUSH = 8; // 0x8
+ field public static final int START_REASON_RESUMED_ACTIVITY = 9; // 0x9
+ field public static final int START_REASON_SERVICE = 10; // 0xa
+ field public static final int START_REASON_START_ACTIVITY = 11; // 0xb
+ field public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2; // 0x2
+ field public static final int START_TIMESTAMP_BIND_APPLICATION = 3; // 0x3
+ field public static final int START_TIMESTAMP_FIRST_FRAME = 4; // 0x4
+ field public static final int START_TIMESTAMP_FULLY_DRAWN = 5; // 0x5
+ field public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1; // 0x1
+ field public static final int START_TIMESTAMP_LAUNCH = 0; // 0x0
+ field public static final int START_TYPE_COLD = 0; // 0x0
+ field public static final int START_TYPE_HOT = 2; // 0x2
+ field public static final int START_TYPE_WARM = 1; // 0x1
+ }
+
public final class AsyncNotedAppOp implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getAttributionTag();
@@ -7697,6 +7755,26 @@
method public final android.os.IBinder onBind(android.content.Intent);
}
+ public final class DevicePolicyIdentifiers {
+ method @NonNull public static String getIdentifierForUserRestriction(@NonNull String);
+ field public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+ field public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+ field public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+ field public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+ field public static final String AUTO_TIME_POLICY = "autoTime";
+ field public static final String BACKUP_SERVICE_POLICY = "backupService";
+ field public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+ field public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+ field public static final String LOCK_TASK_POLICY = "lockTask";
+ field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+ field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+ field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+ field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
+ field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+ field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+ field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
+ }
+
public class DevicePolicyManager {
method public void acknowledgeDeviceCompliant();
method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
@@ -7848,6 +7926,7 @@
method public boolean isResetPasswordTokenActive(android.content.ComponentName);
method public boolean isSafeOperation(int);
method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
+ method public boolean isStatusBarDisabled();
method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
method public boolean isUniqueDeviceAttestationSupported();
method public boolean isUsbDataSignalingEnabled();
@@ -7882,7 +7961,7 @@
method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
- method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public void setCameraDisabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
method public void setCommonCriteriaModeEnabled(@NonNull android.content.ComponentName, boolean);
method public void setConfiguredNetworksLockdownState(@NonNull android.content.ComponentName, boolean);
@@ -8088,6 +8167,7 @@
field @Deprecated public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 64; // 0x40
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
+ field public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 512; // 0x200
field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
@@ -8249,6 +8329,8 @@
ctor public PolicyUpdateResult(int);
method public int getResultCode();
field public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1; // 0x1
+ field public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4; // 0x4
+ field public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3; // 0x3
field public static final int RESULT_FAILURE_UNKNOWN = -1; // 0xffffffff
field public static final int RESULT_POLICY_CLEARED = 2; // 0x2
field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -8261,6 +8343,7 @@
method public final void onReceive(android.content.Context, android.content.Intent);
field public static final String ACTION_DEVICE_POLICY_CHANGED = "android.app.admin.action.DEVICE_POLICY_CHANGED";
field public static final String ACTION_DEVICE_POLICY_SET_RESULT = "android.app.admin.action.DEVICE_POLICY_SET_RESULT";
+ field public static final String EXTRA_ACCOUNT_TYPE = "android.app.admin.extra.ACCOUNT_TYPE";
field public static final String EXTRA_INTENT_FILTER = "android.app.admin.extra.INTENT_FILTER";
field public static final String EXTRA_PACKAGE_NAME = "android.app.admin.extra.PACKAGE_NAME";
field public static final String EXTRA_PERMISSION_NAME = "android.app.admin.extra.PERMISSION_NAME";
@@ -14850,6 +14933,7 @@
method @Nullable public android.graphics.ColorSpace getColorSpace();
method @NonNull public android.graphics.Bitmap.Config getConfig();
method public int getDensity();
+ method @Nullable public android.graphics.Gainmap getGainmap();
method public int getGenerationId();
method @NonNull public android.hardware.HardwareBuffer getHardwareBuffer();
method public int getHeight();
@@ -14865,6 +14949,7 @@
method public int getScaledWidth(int);
method public int getWidth();
method public boolean hasAlpha();
+ method public boolean hasGainmap();
method public boolean hasMipMap();
method public boolean isMutable();
method public boolean isPremultiplied();
@@ -14876,6 +14961,7 @@
method public void setColorSpace(@NonNull android.graphics.ColorSpace);
method public void setConfig(@NonNull android.graphics.Bitmap.Config);
method public void setDensity(int);
+ method public void setGainmap(@Nullable android.graphics.Gainmap);
method public void setHasAlpha(boolean);
method public void setHasMipMap(boolean);
method public void setHeight(int);
@@ -15411,6 +15497,26 @@
ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
}
+ public final class Gainmap {
+ ctor public Gainmap(@NonNull android.graphics.Bitmap);
+ method @NonNull public float getDisplayRatioForFullHdr();
+ method @NonNull public float[] getEpsilonHdr();
+ method @NonNull public float[] getEpsilonSdr();
+ method @NonNull public android.graphics.Bitmap getGainmapContents();
+ method @NonNull public float[] getGamma();
+ method @NonNull public float getMinDisplayRatioForHdrTransition();
+ method @NonNull public float[] getRatioMax();
+ method @NonNull public float[] getRatioMin();
+ method @NonNull public void setDisplayRatioForFullHdr(float);
+ method @NonNull public void setEpsilonHdr(float, float, float);
+ method @NonNull public void setEpsilonSdr(float, float, float);
+ method public void setGainmapContents(@NonNull android.graphics.Bitmap);
+ method @NonNull public void setGamma(float, float, float);
+ method @NonNull public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
+ method @NonNull public void setRatioMax(float, float, float);
+ method @NonNull public void setRatioMin(float, float, float);
+ }
+
public class HardwareBufferRenderer implements java.lang.AutoCloseable {
ctor public HardwareBufferRenderer(@NonNull android.hardware.HardwareBuffer);
method public void close();
@@ -27310,6 +27416,7 @@
method public void resumeRecording();
method public void resumeRecording(@NonNull android.os.Bundle);
method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
+ method public void setTvInteractiveAppView(@Nullable android.media.tv.interactive.TvInteractiveAppView, @Nullable String);
method public void startRecording(@Nullable android.net.Uri);
method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
method public void stopRecording();
@@ -27598,8 +27705,13 @@
method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
method public void onMediaViewSizeChanged(@Px int, @Px int);
- method public void onRecordingStarted(@NonNull String);
+ method public void onRecordingConnectionFailed(@NonNull String, @NonNull String);
+ method public void onRecordingDisconnected(@NonNull String, @NonNull String);
+ method public void onRecordingError(@NonNull String, int);
+ method public void onRecordingScheduled(@NonNull String, @Nullable String);
+ method public void onRecordingStarted(@NonNull String, @Nullable String);
method public void onRecordingStopped(@NonNull String);
+ method public void onRecordingTuned(@NonNull String, @NonNull android.net.Uri);
method public abstract void onRelease();
method public void onResetInteractiveApp();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
@@ -27634,8 +27746,10 @@
method @CallSuper public void requestCurrentChannelUri();
method @CallSuper public void requestCurrentTvInputId();
method @CallSuper public void requestCurrentVideoBounds();
+ method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+ method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
- method @CallSuper public void requestStartRecording(@Nullable android.net.Uri);
+ method @CallSuper public void requestStartRecording(@NonNull String, @Nullable android.net.Uri);
method @CallSuper public void requestStopRecording(@NonNull String);
method @CallSuper public void requestStreamVolume();
method @CallSuper public void requestTimeShiftMode();
@@ -27676,7 +27790,8 @@
method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void notifyError(@NonNull String, @NonNull android.os.Bundle);
- method public void notifyRecordingStarted(@NonNull String);
+ method public void notifyRecordingScheduled(@NonNull String, @Nullable String);
+ method public void notifyRecordingStarted(@NonNull String, @Nullable String);
method public void notifyRecordingStopped(@NonNull String);
method public void notifyTimeShiftCurrentPositionChanged(@NonNull String, long);
method public void notifyTimeShiftPlaybackParams(@NonNull android.media.PlaybackParams);
@@ -27730,8 +27845,10 @@
method public void onRequestCurrentChannelUri(@NonNull String);
method public void onRequestCurrentTvInputId(@NonNull String);
method public void onRequestCurrentVideoBounds(@NonNull String);
+ method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+ method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
- method public void onRequestStartRecording(@NonNull String, @Nullable android.net.Uri);
+ method public void onRequestStartRecording(@NonNull String, @NonNull String, @Nullable android.net.Uri);
method public void onRequestStopRecording(@NonNull String, @NonNull String);
method public void onRequestStreamVolume(@NonNull String);
method public void onRequestTimeShiftMode(@NonNull String);
@@ -33341,6 +33458,7 @@
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED = "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
+ field public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED = "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
field public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
field @Deprecated public static final int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2
@@ -41333,9 +41451,11 @@
method public final android.os.IBinder onBind(android.content.Intent);
method protected abstract void onCancel(android.speech.RecognitionService.Callback);
method public void onCheckRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionService.SupportCallback);
+ method public void onCheckRecognitionSupport(@NonNull android.content.Intent, @NonNull android.content.AttributionSource, @NonNull android.speech.RecognitionService.SupportCallback);
method protected abstract void onStartListening(android.content.Intent, android.speech.RecognitionService.Callback);
method protected abstract void onStopListening(android.speech.RecognitionService.Callback);
method public void onTriggerModelDownload(@NonNull android.content.Intent);
+ method public void onTriggerModelDownload(@NonNull android.content.Intent, @NonNull android.content.AttributionSource);
field public static final String SERVICE_INTERFACE = "android.speech.RecognitionService";
field public static final String SERVICE_META_DATA = "android.speech";
}
@@ -53668,12 +53788,14 @@
method public int getFitInsetsTypes();
method public final CharSequence getTitle();
method public boolean isFitInsetsIgnoringVisibility();
+ method public boolean isHdrConversionEnabled();
method public static boolean mayUseInputMethod(int);
method public void setBlurBehindRadius(@IntRange(from=0) int);
method public void setColorMode(int);
method public void setFitInsetsIgnoringVisibility(boolean);
method public void setFitInsetsSides(int);
method public void setFitInsetsTypes(int);
+ method public void setHdrConversionEnabled(boolean);
method public final void setTitle(CharSequence);
method public void setWallpaperTouchEventsEnabled(boolean);
method public void writeToParcel(android.os.Parcel, int);
@@ -53684,6 +53806,7 @@
field public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
field @NonNull public static final android.os.Parcelable.Creator<android.view.WindowManager.LayoutParams> CREATOR;
field public static final int DIM_AMOUNT_CHANGED = 32; // 0x20
+ field public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION = 1; // 0x1
field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1
field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8
field public static final int FIRST_SYSTEM_WINDOW = 2000; // 0x7d0
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 5406333..1e21c776 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -166,6 +166,7 @@
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setA2dpSuspended(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 57759c6..67aa074 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -277,6 +277,7 @@
field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
+ field public static final String READ_RESTRICTED_STATS = "android.permission.READ_RESTRICTED_STATS";
field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS";
field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
@@ -525,6 +526,7 @@
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
+ method @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
@@ -1204,11 +1206,19 @@
package android.app.admin {
+ public final class AccountTypePolicyKey extends android.app.admin.PolicyKey {
+ method public int describeContents();
+ method @NonNull public String getAccountType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.AccountTypePolicyKey> CREATOR;
+ }
+
public abstract class Authority implements android.os.Parcelable {
method public int describeContents();
}
public final class DeviceAdminAuthority extends android.app.admin.Authority {
+ ctor public DeviceAdminAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminAuthority> CREATOR;
}
@@ -1289,6 +1299,7 @@
field public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = 2; // 0x2
field public static final int EXEMPT_FROM_APP_STANDBY = 0; // 0x0
field public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = 1; // 0x1
+ field public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4; // 0x4
field public static final int EXEMPT_FROM_HIBERNATION = 3; // 0x3
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
@@ -1392,11 +1403,13 @@
}
public final class DpcAuthority extends android.app.admin.Authority {
+ ctor public DpcAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DpcAuthority> CREATOR;
}
public final class EnforcingAdmin implements android.os.Parcelable {
+ ctor public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle);
method public int describeContents();
method @NonNull public android.app.admin.Authority getAuthority();
method @NonNull public String getPackageName();
@@ -1520,6 +1533,7 @@
}
public final class RoleAuthority extends android.app.admin.Authority {
+ ctor public RoleAuthority(@NonNull java.util.Set<java.lang.String>);
method @NonNull public java.util.Set<java.lang.String> getRoles();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.RoleAuthority> CREATOR;
@@ -1540,6 +1554,7 @@
}
public final class UnknownAuthority extends android.app.admin.Authority {
+ ctor public UnknownAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnknownAuthority> CREATOR;
}
@@ -10646,7 +10661,6 @@
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
- field @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY) public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED = "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
field public static final String REBOOT_USERSPACE = "userspace";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f310d8d..bea2bfc 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -512,6 +512,10 @@
package android.app.admin {
+ public final class DeviceAdminAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
+ }
+
public class DevicePolicyManager {
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
@@ -592,21 +596,28 @@
field @Deprecated public static final int STATUS_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
}
+ public final class DpcAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.DpcAuthority DPC_AUTHORITY;
+ }
+
public final class FlagUnion extends android.app.admin.ResolutionMechanism<java.lang.Integer> {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FlagUnion> CREATOR;
+ field @NonNull public static final android.app.admin.FlagUnion FLAG_UNION;
}
public final class MostRecent<V> extends android.app.admin.ResolutionMechanism<V> {
ctor public MostRecent();
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent<?>> CREATOR;
+ field @NonNull public static final android.app.admin.MostRecent<?> MOST_RECENT;
}
public final class MostRestrictive<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
+ method @NonNull public java.util.List<V> getMostToLeastRestrictiveValues();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRestrictive<?>> CREATOR;
}
@@ -627,14 +638,20 @@
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.StringSetUnion> CREATOR;
+ field @NonNull public static final android.app.admin.StringSetUnion STRING_SET_UNION;
}
public final class TopPriority<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
+ method @NonNull public java.util.List<android.app.admin.Authority> getHighestToLowestPriorityAuthorities();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.TopPriority<?>> CREATOR;
}
+ public final class UnknownAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.UnknownAuthority UNKNOWN_AUTHORITY;
+ }
+
public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
ctor public UnsafeStateException(int, int);
method public int getOperation();
@@ -1400,6 +1417,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearGlobalUserPreferredDisplayMode();
method @Nullable public android.view.Display.Mode getGlobalUserPreferredDisplayMode();
method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionMode();
+ method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionModeSetting();
method @NonNull public int[] getSupportedHdrOutputTypes();
method @NonNull public int[] getUserDisabledHdrTypes();
method public boolean isMinimalPostProcessingRequested(int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3c17a33..1d03d84 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -26,8 +26,10 @@
import static java.lang.Character.MIN_VALUE;
+import android.annotation.AnimRes;
import android.annotation.CallSuper;
import android.annotation.CallbackExecutor;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
@@ -108,6 +110,7 @@
import android.util.Dumpable;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -1006,6 +1009,25 @@
*/
public static final int FULLSCREEN_MODE_REQUEST_ENTER = 1;
+ /** @hide */
+ @IntDef(prefix = { "OVERRIDE_TRANSITION_" }, value = {
+ OVERRIDE_TRANSITION_OPEN,
+ OVERRIDE_TRANSITION_CLOSE
+ })
+ public @interface OverrideTransition {}
+
+ /**
+ * Request type of {@link #overrideActivityTransition(int, int, int)} or
+ * {@link #overrideActivityTransition(int, int, int, int)}, to override the
+ * opening transition.
+ */
+ public static final int OVERRIDE_TRANSITION_OPEN = 0;
+ /**
+ * Request type of {@link #overrideActivityTransition(int, int, int)} or
+ * {@link #overrideActivityTransition(int, int, int, int)}, to override the
+ * closing transition.
+ */
+ public static final int OVERRIDE_TRANSITION_CLOSE = 1;
private boolean mShouldDockBigOverlays;
private UiTranslationController mUiTranslationController;
@@ -6462,6 +6484,124 @@
}
/**
+ * Customizes the animation for the activity transition with this activity. This can be called
+ * at any time while the activity still alive.
+ *
+ * <p> This is a more robust method of overriding the transition animation at runtime without
+ * relying on {@link #overridePendingTransition(int, int)} which doesn't work for predictive
+ * back. However, the animation set from {@link #overridePendingTransition(int, int)} still
+ * has higher priority when the system is looking for the next transition animation.</p>
+ * <p> The animations resources set by this method will be chosen if and only if the activity is
+ * on top of the task while activity transitions are being played.
+ * For example, if we want to customize the opening transition when launching Activity B which
+ * gets started from Activity A, we should call this method inside B's onCreate with
+ * {@code overrideType = OVERRIDE_TRANSITION_OPEN} because the Activity B will on top of the
+ * task. And if we want to customize the closing transition when finishing Activity B and back
+ * to Activity A, since B is still is above A, we should call this method in Activity B with
+ * {@code overrideType = OVERRIDE_TRANSITION_CLOSE}. </p>
+ *
+ * <p> If an Activity has called this method, and it also set another activity animation
+ * by {@link Window#setWindowAnimations(int)}, the system will choose the animation set from
+ * this method.</p>
+ *
+ * <p> Note that {@link Window#setWindowAnimations},
+ * {@link #overridePendingTransition(int, int)} and this method will be ignored if the Activity
+ * is started with {@link ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])}. Also
+ * note that this method can only be used to customize cross-activity transitions but not
+ * cross-task transitions which are fully non-customizable as of Android 11.</p>
+ *
+ * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} This animation will be used when
+ * starting/entering an activity. {@code OVERRIDE_TRANSITION_CLOSE} This
+ * animation will be used when finishing/closing an activity.
+ * @param enterAnim A resource ID of the animation resource to use for the incoming activity.
+ * Use 0 for no animation.
+ * @param exitAnim A resource ID of the animation resource to use for the outgoing activity.
+ * Use 0 for no animation.
+ *
+ * @see #overrideActivityTransition(int, int, int, int)
+ * @see #clearOverrideActivityTransition(int)
+ * @see OnBackInvokedCallback
+ * @see #overridePendingTransition(int, int)
+ * @see Window#setWindowAnimations(int)
+ * @see ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])
+ */
+ public void overrideActivityTransition(@OverrideTransition int overrideType,
+ @AnimRes int enterAnim, @AnimRes int exitAnim) {
+ overrideActivityTransition(overrideType, enterAnim, exitAnim, Color.TRANSPARENT);
+ }
+
+ /**
+ * Customizes the animation for the activity transition with this activity. This can be called
+ * at any time while the activity still alive.
+ *
+ * <p> This is a more robust method of overriding the transition animation at runtime without
+ * relying on {@link #overridePendingTransition(int, int)} which doesn't work for predictive
+ * back. However, the animation set from {@link #overridePendingTransition(int, int)} still
+ * has higher priority when the system is looking for the next transition animation.</p>
+ * <p> The animations resources set by this method will be chosen if and only if the activity is
+ * on top of the task while activity transitions are being played.
+ * For example, if we want to customize the opening transition when launching Activity B which
+ * gets started from Activity A, we should call this method inside B's onCreate with
+ * {@code overrideType = OVERRIDE_TRANSITION_OPEN} because the Activity B will on top of the
+ * task. And if we want to customize the closing transition when finishing Activity B and back
+ * to Activity A, since B is still is above A, we should call this method in Activity B with
+ * {@code overrideType = OVERRIDE_TRANSITION_CLOSE}. </p>
+ *
+ * <p> If an Activity has called this method, and it also set another activity animation
+ * by {@link Window#setWindowAnimations(int)}, the system will choose the animation set from
+ * this method.</p>
+ *
+ * <p> Note that {@link Window#setWindowAnimations},
+ * {@link #overridePendingTransition(int, int)} and this method will be ignored if the Activity
+ * is started with {@link ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])}. Also
+ * note that this method can only be used to customize cross-activity transitions but not
+ * cross-task transitions which are fully non-customizable as of Android 11.</p>
+ *
+ * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} This animation will be used when
+ * starting/entering an activity. {@code OVERRIDE_TRANSITION_CLOSE} This
+ * animation will be used when finishing/closing an activity.
+ * @param enterAnim A resource ID of the animation resource to use for the incoming activity.
+ * Use 0 for no animation.
+ * @param exitAnim A resource ID of the animation resource to use for the outgoing activity.
+ * Use 0 for no animation.
+ * @param backgroundColor The background color to use for the background during the animation
+ * if the animation requires a background. Set to
+ * {@link Color#TRANSPARENT} to not override the default color.
+ * @see #overrideActivityTransition(int, int, int)
+ * @see #clearOverrideActivityTransition(int)
+ * @see OnBackInvokedCallback
+ * @see #overridePendingTransition(int, int)
+ * @see Window#setWindowAnimations(int)
+ * @see ActivityOptions#makeSceneTransitionAnimation(Activity, Pair[])
+ */
+ public void overrideActivityTransition(@OverrideTransition int overrideType,
+ @AnimRes int enterAnim, @AnimRes int exitAnim, @ColorInt int backgroundColor) {
+ if (overrideType != OVERRIDE_TRANSITION_OPEN && overrideType != OVERRIDE_TRANSITION_CLOSE) {
+ throw new IllegalArgumentException("Override type must be either open or close");
+ }
+
+ ActivityClient.getInstance().overrideActivityTransition(mToken,
+ overrideType == OVERRIDE_TRANSITION_OPEN, enterAnim, exitAnim, backgroundColor);
+ }
+
+ /**
+ * Clears the animations which are set from {@link #overrideActivityTransition}.
+ * @param overrideType {@code OVERRIDE_TRANSITION_OPEN} clear the animation set for starting a
+ * new activity. {@code OVERRIDE_TRANSITION_CLOSE} clear the animation set
+ * for finishing an activity.
+ *
+ * @see #overrideActivityTransition(int, int, int)
+ * @see #overrideActivityTransition(int, int, int, int)
+ */
+ public void clearOverrideActivityTransition(@OverrideTransition int overrideType) {
+ if (overrideType != OVERRIDE_TRANSITION_OPEN && overrideType != OVERRIDE_TRANSITION_CLOSE) {
+ throw new IllegalArgumentException("Override type must be either open or close");
+ }
+ ActivityClient.getInstance().clearOverrideActivityTransition(mToken,
+ overrideType == OVERRIDE_TRANSITION_OPEN);
+ }
+
+ /**
* Call immediately after one of the flavors of {@link #startActivity(Intent)}
* or {@link #finish} to specify an explicit transition animation to
* perform next.
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index aa868a7..5354a44 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -486,6 +486,24 @@
}
}
+ void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+ int backgroundColor) {
+ try {
+ getActivityClientController().overrideActivityTransition(
+ token, open, enterAnim, exitAnim, backgroundColor);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ void clearOverrideActivityTransition(IBinder token, boolean open) {
+ try {
+ getActivityClientController().clearOverrideActivityTransition(token, open);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim,
int backgroundColor) {
try {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f408916..42d056c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3676,6 +3676,123 @@
}
/**
+ * Return a list of {@link ApplicationStartInfo} records containing the information about the
+ * most recent app startups.
+ *
+ * <p class="note"> Note: System stores this historical information in a ring buffer and only
+ * the most recent records will be returned. </p>
+ *
+ * @param maxNum The maximum number of results to be returned; a value of 0
+ * means to ignore this parameter and return all matching records. If fewer
+ * records exist, all existing records will be returned.
+ *
+ * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+ * the order from most recent to least recent.
+ */
+ @NonNull
+ public List<ApplicationStartInfo> getHistoricalProcessStartReasons(
+ @IntRange(from = 0) int maxNum) {
+ try {
+ ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+ .getHistoricalProcessStartReasons(null, maxNum, mContext.getUserId());
+ return startInfos == null ? Collections.emptyList() : startInfos.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return a list of {@link ApplicationStartInfo} records containing the information about the
+ * most recent app startups.
+ *
+ * <p class="note"> Note: System stores this historical information in a ring buffer and only
+ * the most recent records will be returned. </p>
+ *
+ * @param packageName Package name for which app startups to receive.
+ * @param maxNum The maximum number of results to be returned; a value of 0
+ * means to ignore this parameter and return all matching records. If fewer
+ * records exist, all existing records will be returned.
+ *
+ * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+ * the order from most recent to least recent.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(Manifest.permission.DUMP)
+ public List<ApplicationStartInfo> getExternalHistoricalProcessStartReasons(
+ @NonNull String packageName, @IntRange(from = 0) int maxNum) {
+ try {
+ ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+ .getHistoricalProcessStartReasons(packageName, maxNum, mContext.getUserId());
+ return startInfos == null ? Collections.emptyList() : startInfos.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback to receive {@link ApplicationStartInfo} object once recording of startup related
+ * metrics is complete.
+ * Use with {@link #setApplicationStartInfoCompleteListener}.
+ */
+ public interface ApplicationStartInfoCompleteListener {
+ /** {@link ApplicationStartInfo} is complete, no more info will be added. */
+ void onApplicationStartInfoComplete(@NonNull ApplicationStartInfo applicationStartInfo);
+ }
+
+ /**
+ * Sets a callback to be notified when the {@link ApplicationStartInfo} records of this startup
+ * are complete.
+ *
+ * <p class="note"> Note: callback will not wait for {@link Activity#reportFullyDrawn} to occur.
+ * Timestamp for fully drawn may be added after callback occurs. Set callback after invoking
+ * {@link Activity#reportFullyDrawn} if timestamp for fully drawn is required.</p>
+ *
+ * <p class="note"> Note: if start records have already been retrieved, the callback will be
+ * invoked immediately on the specified executor with the previously resolved AppStartInfo.</p>
+ *
+ * <p class="note"> Note: callback is asynchronous and should be made from a background thread.
+ * </p>
+ *
+ * @param executor The executor on which the listener should be called.
+ * @param listener Callback to be called when collection of {@link ApplicationStartInfo} is
+ * complete. Will replace existing listener if one is already attached.
+ *
+ * @throws IllegalArgumentException if executor or listener are null.
+ */
+ public void setApplicationStartInfoCompleteListener(@NonNull final Executor executor,
+ @NonNull final ApplicationStartInfoCompleteListener listener) {
+ Preconditions.checkNotNull(executor, "executor cannot be null");
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ IApplicationStartInfoCompleteListener callback =
+ new IApplicationStartInfoCompleteListener.Stub() {
+ @Override
+ public void onApplicationStartInfoComplete(ApplicationStartInfo applicationStartInfo) {
+ executor.execute(() ->
+ listener.onApplicationStartInfoComplete(applicationStartInfo));
+ }
+ };
+ try {
+ getService().setApplicationStartInfoCompleteListener(callback, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes the callback set by {@link #setApplicationStartInfoCompleteListener} if there is one.
+ */
+ public void removeApplicationStartInfoCompleteListener() {
+ try {
+ getService().removeApplicationStartInfoCompleteListener(mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return a list of {@link ApplicationExitInfo} records containing the reasons for the most
* recent app deaths.
*
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0fa1a37..2ad5c20 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -963,4 +963,12 @@
* @hide
*/
public abstract boolean canHoldWakeLocksInDeepDoze(int uid, int procstate);
+
+ /**
+ * Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed
+ * even if the profile is disabled - it should only be called by
+ * {@link com.android.server.devicepolicy.DevicePolicyManagerService} when starting a profile
+ * while it's being created.
+ */
+ public abstract boolean startProfileEvenWhenDisabled(@UserIdInt int userId);
}
diff --git a/core/java/android/app/ApplicationStartInfo.aidl b/core/java/android/app/ApplicationStartInfo.aidl
new file mode 100644
index 0000000..4322c7e
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable ApplicationStartInfo;
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
new file mode 100644
index 0000000..794c55e
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Provide information related to a processes startup. */
+public final class ApplicationStartInfo implements Parcelable {
+
+ /**
+ * State indicating process startup has started. Some information is available in
+ * {@link ApplicationStartInfo} and more will be added.
+ */
+ public static final int STARTUP_STATE_STARTED = 0;
+
+ /**
+ * State indicating process startup has failed. Startup information in
+ * {@link ApplicationStartInfo} is incomplete, but no more will be added.
+ */
+ public static final int STARTUP_STATE_ERROR = 1;
+
+ /**
+ * State indicating process startup has made it to first frame draw. Startup
+ * information in {@link ApplicationStartInfo} is complete with potential exception
+ * of fully drawn timestamp which is not guaranteed to be set.
+ */
+ public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2;
+
+ /** Process started due to alarm. */
+ public static final int START_REASON_ALARM = 0;
+
+ /** Process started to run backup. */
+ public static final int START_REASON_BACKUP = 1;
+
+ /** Process started due to boot complete. */
+ public static final int START_REASON_BOOT_COMPLETE = 2;
+
+ /** Process started due to broadcast received. */
+ public static final int START_REASON_BROADCAST = 3;
+
+ /** Process started due to access of ContentProvider */
+ public static final int START_REASON_CONTENT_PROVIDER = 4;
+
+ /** * Process started to run scheduled job. */
+ public static final int START_REASON_JOB = 5;
+
+ /** Process started due to click app icon or widget from launcher. */
+ public static final int START_REASON_LAUNCHER = 6;
+
+ /** Process started not for any of the listed reasons. */
+ public static final int START_REASON_OTHER = 7;
+
+ /** Process started due to push message. */
+ public static final int START_REASON_PUSH = 8;
+
+ /** Process started to resume activity. */
+ public static final int START_REASON_RESUMED_ACTIVITY = 9;
+
+ /** Process service started. */
+ public static final int START_REASON_SERVICE = 10;
+
+ /** Process started due to Activity started for any reason not explicitly listed. */
+ public static final int START_REASON_START_ACTIVITY = 11;
+
+ /** Process started from scratch. */
+ public static final int START_TYPE_COLD = 0;
+
+ /** Process retained minimally SavedInstanceState. */
+ public static final int START_TYPE_WARM = 1;
+
+ /** Process brought back to foreground. */
+ public static final int START_TYPE_HOT = 2;
+
+ /**
+ * Default. The system always creates a new instance of the activity in the target task and
+ * routes the intent to it.
+ */
+ public static final int LAUNCH_MODE_STANDARD = 0;
+
+ /**
+ * If an instance of the activity already exists at the top of the target task, the system
+ * routes the intent to that instance through a call to its onNewIntent() method, rather than
+ * creating a new instance of the activity.
+ */
+ public static final int LAUNCH_MODE_SINGLE_TOP = 1;
+
+ /**
+ * The system creates the activity at the root of a new task or locates the activity on an
+ * existing task with the same affinity. If an instance of the activity already exists and is at
+ * the root of the task, the system routes the intent to existing instance through a call to its
+ * onNewIntent() method, rather than creating a new one.
+ */
+ public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2;
+
+ /**
+ * Same as "singleTask", except that the system doesn't launch any other activities into the
+ * task holding the instance. The activity is always the single and only member of its task.
+ */
+ public static final int LAUNCH_MODE_SINGLE_TASK = 3;
+
+ /**
+ * The activity can only be running as the root activity of the task, the first activity that
+ * created the task, and therefore there will only be one instance of this activity in a task;
+ * but activity can be instantiated multiple times in different tasks.
+ */
+ public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4;
+
+ /** Clock monotonic timestamp of launch started. */
+ public static final int START_TIMESTAMP_LAUNCH = 0;
+
+ /** Clock monotonic timestamp of finish java classloading. */
+ public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1;
+
+ /** Clock monotonic timestamp of Application onCreate called. */
+ public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2;
+
+ /** Clock monotonic timestamp of bindApplication called. */
+ public static final int START_TIMESTAMP_BIND_APPLICATION = 3;
+
+ /** Clock monotonic timestamp of first frame drawn. */
+ public static final int START_TIMESTAMP_FIRST_FRAME = 4;
+
+ /** Clock monotonic timestamp of reportFullyDrawn called by application. */
+ public static final int START_TIMESTAMP_FULLY_DRAWN = 5;
+
+ /**
+ * @see #getStartupState
+ */
+ private @StartupState int mStartupState;
+
+ /**
+ * @see #getPid
+ */
+ private int mPid;
+
+ /**
+ * @see #getRealUid
+ */
+ private int mRealUid;
+
+ /**
+ * @see #getPackageUid
+ */
+ private int mPackageUid;
+
+ /**
+ * @see #getDefiningUid
+ */
+ private int mDefiningUid;
+
+ /**
+ * @see #getProcessName
+ */
+ private String mProcessName;
+
+ /**
+ * @see #getReason
+ */
+ private @StartReason int mReason;
+
+ /**
+ * @see #getStartupTimestamps
+ */
+ private Map<@StartupTimestamp Integer, Long> mStartupTimestampsNs;
+
+ /**
+ * @see #getStartType
+ */
+ private @StartType int mStartType;
+
+ /**
+ * @see #getStartIntent
+ */
+ private Intent mStartIntent;
+
+ /**
+ * @see #getLaunchMode
+ */
+ private @LaunchMode int mLaunchMode;
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"STARTUP_STATE_"},
+ value = {
+ STARTUP_STATE_STARTED,
+ STARTUP_STATE_ERROR,
+ STARTUP_STATE_FIRST_FRAME_DRAWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartupState {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_REASON_"},
+ value = {
+ START_REASON_ALARM,
+ START_REASON_BACKUP,
+ START_REASON_BOOT_COMPLETE,
+ START_REASON_BROADCAST,
+ START_REASON_CONTENT_PROVIDER,
+ START_REASON_JOB,
+ START_REASON_LAUNCHER,
+ START_REASON_OTHER,
+ START_REASON_PUSH,
+ START_REASON_RESUMED_ACTIVITY,
+ START_REASON_SERVICE,
+ START_REASON_START_ACTIVITY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartReason {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_TYPE_"},
+ value = {
+ START_TYPE_COLD,
+ START_TYPE_WARM,
+ START_TYPE_HOT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartType {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"LAUNCH_MODE_"},
+ value = {
+ LAUNCH_MODE_STANDARD,
+ LAUNCH_MODE_SINGLE_TOP,
+ LAUNCH_MODE_SINGLE_INSTANCE,
+ LAUNCH_MODE_SINGLE_TASK,
+ LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LaunchMode {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_TIMESTAMP_"},
+ value = {
+ START_TIMESTAMP_LAUNCH,
+ START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE,
+ START_TIMESTAMP_APPLICATION_ONCREATE,
+ START_TIMESTAMP_BIND_APPLICATION,
+ START_TIMESTAMP_FULLY_DRAWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface StartupTimestamp {}
+
+ /**
+ * @see #getStartupState
+ * @hide
+ */
+ public void setStartupState(final @StartupState int startupState) {
+ mStartupState = startupState;
+ }
+
+ /**
+ * @see #getPid
+ * @hide
+ */
+ public void setPid(final int pid) {
+ mPid = pid;
+ }
+
+ /**
+ * @see #getRealUid
+ * @hide
+ */
+ public void setRealUid(final int uid) {
+ mRealUid = uid;
+ }
+
+ /**
+ * @see #getPackageUid
+ * @hide
+ */
+ public void setPackageUid(final int uid) {
+ mPackageUid = uid;
+ }
+
+ /**
+ * @see #getDefiningUid
+ * @hide
+ */
+ public void setDefiningUid(final int uid) {
+ mDefiningUid = uid;
+ }
+
+ /**
+ * @see #getProcessName
+ * @hide
+ */
+ public void setProcessName(final String processName) {
+ mProcessName = intern(processName);
+ }
+
+ /**
+ * @see #getReason
+ * @hide
+ */
+ public void setReason(@StartReason int reason) {
+ mReason = reason;
+ }
+
+ /**
+ * @see #getStartupTimestamps
+ * @hide
+ */
+ public void addStartupTimestamp(@StartupTimestamp int key, long timestampNs) {
+ if (mStartupTimestampsNs == null) {
+ mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+ }
+ mStartupTimestampsNs.put(key, timestampNs);
+ }
+
+ /**
+ * @see #getStartType
+ * @hide
+ */
+ public void setStartType(@StartType int startType) {
+ mStartType = startType;
+ }
+
+ /**
+ * @see #getStartIntent
+ * @hide
+ */
+ public void setIntent(Intent startIntent) {
+ mStartIntent = startIntent;
+ }
+
+ /**
+ * @see #getLaunchMode
+ * @hide
+ */
+ public void setLaunchMode(@LaunchMode int launchMode) {
+ mLaunchMode = launchMode;
+ }
+
+ /**
+ * Current state of startup.
+ *
+ * Can be used to determine whether the object will have additional fields added as it may be
+ * queried before all data is collected.
+ *
+ * <p class="note"> Note: field will always be set and available.</p>
+ */
+ public @StartupState int getStartupState() {
+ return mStartupState;
+ }
+
+ /**
+ * The process id.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getPid() {
+ return mPid;
+ }
+
+ /**
+ * The kernel user identifier of the process, most of the time the system uses this to do access
+ * control checks. It's typically the uid of the package where the component is running from,
+ * except the case of isolated process, where this field identifies the kernel user identifier
+ * that this process is actually running with, while the {@link #getPackageUid} identifies the
+ * kernel user identifier that is assigned at the package installation time.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getRealUid() {
+ return mRealUid;
+ }
+
+ /**
+ * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the
+ * package installation time.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getPackageUid() {
+ return mPackageUid;
+ }
+
+ /**
+ * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
+ * {@link #getPackageUid}, if an external service has the {@link
+ * android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code>
+ * true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}
+ * - in this case, this field here will be the kernel user identifier of the external service
+ * provider.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getDefiningUid() {
+ return mDefiningUid;
+ }
+
+ /**
+ * The actual process name it was running with.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @NonNull String getProcessName() {
+ return mProcessName;
+ }
+
+ /**
+ * The reason code of what triggered the process's start.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @StartReason int getReason() {
+ return mReason;
+ }
+
+ /**
+ * Various clock monotonic timestamps in nanoseconds throughout the startup process.
+ *
+ * <p class="note"> Note: different timestamps will be available for different values of
+ * {@link #getStartupState}:
+ *
+ * (Subsequent rows contain all timestamps of proceding states.)
+ *
+ * For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be
+ * available.
+ * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
+ * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
+ * {@link #START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE}, {@link #START_TIMESTAMP_APPLICATION_ONCREATE},
+ * {@link #START_TIMESTAMP_BIND_APPLICATION}, and {@link #START_TIMESTAMP_FIRST_FRAME} will
+ * additionally be available.
+ *
+ * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
+ * dependant on devloper calling {@link Activity#reportFullyDrawn}.
+ * </p>
+ */
+ public @NonNull Map<@StartupTimestamp Integer, Long> getStartupTimestamps() {
+ if (mStartupTimestampsNs == null) {
+ mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+ }
+ return mStartupTimestampsNs;
+ }
+
+ /**
+ * The state of the app at startup.
+ *
+ * <p class="note"> Note: field will be set for {@link #getStartupState} value
+ * {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p>
+ */
+ public @StartType int getStartType() {
+ return mStartType;
+ }
+
+ /**
+ * The intent used to launch the application.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ @SuppressLint("IntentBuilderName")
+ @Nullable
+ public Intent getIntent() {
+ return mStartIntent;
+ }
+
+ /**
+ * An instruction on how the activity should be launched. There are five modes that work in
+ * conjunction with activity flags in Intent objects to determine what should happen when the
+ * activity is called upon to handle an intent.
+ *
+ * Modes:
+ * {@link #LAUNCH_MODE_STANDARD}
+ * {@link #LAUNCH_MODE_SINGLE_TOP}
+ * {@link #LAUNCH_MODE_SINGLE_INSTANCE}
+ * {@link #LAUNCH_MODE_SINGLE_TASK}
+ * {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK}
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @LaunchMode int getLaunchMode() {
+ return mLaunchMode;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mStartupState);
+ dest.writeInt(mPid);
+ dest.writeInt(mRealUid);
+ dest.writeInt(mPackageUid);
+ dest.writeInt(mDefiningUid);
+ dest.writeString(mProcessName);
+ dest.writeInt(mReason);
+ dest.writeInt(mStartupTimestampsNs.size());
+ for (@StartupTimestamp int key : mStartupTimestampsNs.keySet()) {
+ dest.writeInt(key);
+ dest.writeLong(mStartupTimestampsNs.get(key));
+ }
+ dest.writeInt(mStartType);
+ dest.writeParcelable(mStartIntent, flags);
+ dest.writeInt(mLaunchMode);
+ }
+
+ /** @hide */
+ public ApplicationStartInfo() {}
+
+ /** @hide */
+ public ApplicationStartInfo(ApplicationStartInfo other) {
+ mStartupState = other.mStartupState;
+ mPid = other.mPid;
+ mRealUid = other.mRealUid;
+ mPackageUid = other.mPackageUid;
+ mDefiningUid = other.mDefiningUid;
+ mProcessName = other.mProcessName;
+ mReason = other.mReason;
+ mStartupTimestampsNs = other.mStartupTimestampsNs;
+ mStartType = other.mStartType;
+ mStartIntent = other.mStartIntent;
+ mLaunchMode = other.mLaunchMode;
+ }
+
+ private ApplicationStartInfo(@NonNull Parcel in) {
+ mStartupState = in.readInt();
+ mPid = in.readInt();
+ mRealUid = in.readInt();
+ mPackageUid = in.readInt();
+ mDefiningUid = in.readInt();
+ mProcessName = intern(in.readString());
+ mReason = in.readInt();
+ int starupTimestampCount = in.readInt();
+ for (int i = 0; i < starupTimestampCount; i++) {
+ int key = in.readInt();
+ long val = in.readLong();
+ addStartupTimestamp(key, val);
+ }
+ mStartType = in.readInt();
+ mStartIntent =
+ in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
+ mLaunchMode = in.readInt();
+ }
+
+ private static String intern(@Nullable String source) {
+ return source != null ? source.intern() : null;
+ }
+
+ public @NonNull static final Creator<ApplicationStartInfo> CREATOR =
+ new Creator<ApplicationStartInfo>() {
+ @Override
+ public ApplicationStartInfo createFromParcel(Parcel in) {
+ return new ApplicationStartInfo(in);
+ }
+
+ @Override
+ public ApplicationStartInfo[] newArray(int size) {
+ return new ApplicationStartInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 03646c6..5e40399 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -121,6 +121,9 @@
oneway void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
oneway void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
oneway void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
+ oneway void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+ int backgroundColor);
+ oneway void clearOverrideActivityTransition(IBinder token, boolean open);
/**
* Overrides the animation of activity pending transition. This call is not one-way because
* the method is usually used after startActivity or Activity#finish. If this is non-blocking,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c5c3d30..29d80f8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,10 +19,12 @@
import android.app.ActivityManager;
import android.app.ActivityManager.PendingIntentInfo;
import android.app.ActivityTaskManager;
+import android.app.ApplicationStartInfo;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.app.ContentProviderHolder;
import android.app.GrantedUriPermission;
+import android.app.IApplicationStartInfoCompleteListener;
import android.app.IApplicationThread;
import android.app.IActivityController;
import android.app.IAppTask;
@@ -93,7 +95,7 @@
// below block of transactions.
// Since these transactions are also called from native code, these must be kept in sync with
- // the ones in frameworks/native/libs/binder/include/binder/IActivityManager.h
+ // the ones in frameworks/native/libs/binder/include_activitymanager/binder/ActivityManager.h
// =============== Beginning of transactions used on native side as well ======================
ParcelFileDescriptor openContentUri(in String uriString);
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
@@ -485,8 +487,18 @@
// Start of L transactions
String getTagForIntentSender(in IIntentSender sender, in String prefix);
+
+ /**
+ * Starts a user in the background (i.e., while another user is running in the foreground).
+ *
+ * Notice that a background user is "invisible" and cannot launch activities. Starting on
+ * Android U, all users started with this method are invisible, even profiles (prior to Android
+ * U, profiles started with this method would be visible if its parent was the current user) -
+ * if you want to start a profile visible, you should call {@code startProfile()} instead.
+ */
@UnsupportedAppUsage
boolean startUserInBackground(int userid);
+
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
boolean isInLockTaskMode();
@UnsupportedAppUsage
@@ -634,6 +646,45 @@
void appNotResponding(String reason);
/**
+ * Return a list of {@link ApplicationStartInfo} records.
+ *
+ * <p class="note"> Note: System stores historical information in a ring buffer, older
+ * records would be overwritten by newer records. </p>
+ *
+ * @param packageName Optional, an empty value means match all packages belonging to the
+ * caller's UID. If this package belongs to another UID, you must hold
+ * {@link android.Manifest.permission#DUMP} in order to retrieve it.
+ * @param maxNum Optional, the maximum number of results should be returned; A value of 0
+ * means to ignore this parameter and return all matching records
+ * @param userId The userId in the multi-user environment.
+ *
+ * @return a list of {@link ApplicationStartInfo} records with the matching criteria, sorted in
+ * the order from most recent to least recent.
+ */
+ ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(String packageName,
+ int maxNum, int userId);
+
+
+ /**
+ * Sets a callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+ *
+ * <p class="note"> Note: completion of startup is no guaranteed and as such this callback may not occur.</p>
+ *
+ * @param listener A listener to for the callback upon completion of startup data collection.
+ * @param userId The userId in the multi-user environment.
+ */
+ void setApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
+ int userId);
+
+
+ /**
+ * Removes callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+ *
+ * @param userId The userId in the multi-user environment.
+ */
+ void removeApplicationStartInfoCompleteListener(int userId);
+
+ /**
* Return a list of {@link ApplicationExitInfo} records.
*
* <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/IApplicationStartInfoCompleteListener.aidl b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
new file mode 100644
index 0000000..0f0d919
--- /dev/null
+++ b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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 android.app.ApplicationStartInfo;
+
+/**
+ * Notify the client when compilation of app start info is complete.
+ * Will not be called in case of an error that disrupts startup.
+ * @param applicationStartInfo the completed ApplicationStartInfo object.
+ *
+ * @hide
+ */
+interface IApplicationStartInfoCompleteListener {
+ void onApplicationStartInfoComplete(in ApplicationStartInfo applicationStartInfo);
+}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 824c7cc..e72b141 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -4,7 +4,7 @@
# ActivityManager
per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 64538ec..6d80a44 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1570,7 +1570,7 @@
new CachedServiceFetcher<SharedConnectivityManager>() {
@Override
public SharedConnectivityManager createService(ContextImpl ctx) {
- return new SharedConnectivityManager(ctx);
+ return SharedConnectivityManager.create(ctx);
}
});
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index f133c8a..0bdc222 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -218,6 +218,23 @@
"file_patterns": [
"(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
]
+ },
+ {
+ "name": "HdmiCecTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.hardware.hdmi"
+ }
+ ],
+ "file_patterns": [
+ "(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
+ ]
}
],
"presubmit-large": [
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
new file mode 100644
index 0000000..14494d7
--- /dev/null
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 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.admin;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_ACCOUNT_TYPE;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain account type
+ * (e.g. {@link DevicePolicyManager#setAccountManagementDisabled}).
+ *
+ * @hide
+ */
+@SystemApi
+public final class AccountTypePolicyKey extends PolicyKey {
+ private static final String ATTR_ACCOUNT_TYPE = "account-type";
+
+ private final String mAccountType;
+
+ /**
+ * @hide
+ */
+ public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
+ super(key);
+ mAccountType = Objects.requireNonNull((accountType));
+ }
+
+ private AccountTypePolicyKey(Parcel source) {
+ super(source.readString());
+ mAccountType = source.readString();
+ }
+
+ /**
+ * @hide
+ */
+ public AccountTypePolicyKey(String key) {
+ super(key);
+ mAccountType = null;
+ }
+
+ /**
+ * Returns the account type this policy relates to.
+ */
+ @NonNull
+ public String getAccountType() {
+ return mAccountType;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_POLICY_IDENTIFIER, getIdentifier());
+ serializer.attribute(/* namespace= */ null, ATTR_ACCOUNT_TYPE, mAccountType);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public AccountTypePolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String policyKey = parser.getAttributeValue(/* namespace= */ null,
+ ATTR_POLICY_IDENTIFIER);
+ String accountType = parser.getAttributeValue(/* namespace= */ null, ATTR_ACCOUNT_TYPE);
+ return new AccountTypePolicyKey(policyKey, accountType);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToBundle(Bundle bundle) {
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+ Bundle extraPolicyParams = new Bundle();
+ extraPolicyParams.putString(EXTRA_ACCOUNT_TYPE, mAccountType);
+ bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AccountTypePolicyKey other = (AccountTypePolicyKey) o;
+ return Objects.equals(getIdentifier(), other.getIdentifier())
+ && Objects.equals(mAccountType, other.mAccountType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getIdentifier(), mAccountType);
+ }
+
+ @Override
+ public String toString() {
+ return "AccountTypePolicyKey{mPolicyKey= " + getIdentifier()
+ + "; mAccountType= " + mAccountType + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getIdentifier());
+ dest.writeString(mAccountType);
+ }
+
+ @NonNull
+ public static final Creator<AccountTypePolicyKey> CREATOR =
+ new Creator<AccountTypePolicyKey>() {
+ @Override
+ public AccountTypePolicyKey createFromParcel(Parcel source) {
+ return new AccountTypePolicyKey(source);
+ }
+
+ @Override
+ public AccountTypePolicyKey[] newArray(int size) {
+ return new AccountTypePolicyKey[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/DeviceAdminAuthority.java b/core/java/android/app/admin/DeviceAdminAuthority.java
index 5d1ff11..d363147 100644
--- a/core/java/android/app/admin/DeviceAdminAuthority.java
+++ b/core/java/android/app/admin/DeviceAdminAuthority.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -31,11 +32,18 @@
public final class DeviceAdminAuthority extends Authority {
/**
+ * Object representing a device admin authority.
+ *
* @hide
*/
+ @TestApi
+ @NonNull
public static final DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY = new DeviceAdminAuthority();
- private DeviceAdminAuthority() {}
+ /**
+ * Creates an authority that represents a device admin.
+ */
+ public DeviceAdminAuthority() {}
@Override
public String toString() {
@@ -44,12 +52,13 @@
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -65,7 +74,7 @@
new Creator<DeviceAdminAuthority>() {
@Override
public DeviceAdminAuthority createFromParcel(Parcel source) {
- return new DeviceAdminAuthority();
+ return DEVICE_ADMIN_AUTHORITY;
}
@Override
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
new file mode 100644
index 0000000..f6b070a
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 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.admin;
+
+import android.annotation.NonNull;
+import android.os.UserManager;
+
+import java.util.Objects;
+
+/**
+ * Class containing identifiers for policy APIs in {@link DevicePolicyManager}, for example they
+ * will be passed in {@link PolicyUpdatesReceiver#onPolicySetResult} and
+ * {@link PolicyUpdatesReceiver#onPolicyChanged} to communicate updates of a certain policy back
+ * to the admin.
+ */
+public final class DevicePolicyIdentifiers {
+
+ private DevicePolicyIdentifiers() {}
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAutoTimeZoneEnabled}.
+ */
+ public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPermissionGrantState}.
+ */
+ public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
+ */
+ public static final String LOCK_TASK_POLICY = "lockTask";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setUserControlDisabledPackages}.
+ */
+ public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
+ "userControlDisabledPackages";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addPersistentPreferredActivity}.
+ */
+ public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
+ "persistentPreferredActivity";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setUninstallBlocked}.
+ */
+ public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setApplicationRestrictions}.
+ */
+ public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setResetPasswordToken}.
+ */
+ public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAccountManagementDisabled}.
+ */
+ public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setApplicationHidden}.
+ */
+ public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setCameraDisabled}.
+ */
+ public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setStatusBarDisabled}.
+ */
+ public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPackagesSuspended}.
+ */
+ public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setKeyguardDisabledFeatures}.
+ */
+ public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAutoTimeEnabled}.
+ */
+ public static final String AUTO_TIME_POLICY = "autoTime";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setBackupServiceEnabled}.
+ */
+ public static final String BACKUP_SERVICE_POLICY = "backupService";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPermittedInputMethods}.
+ *
+ * @hide
+ */
+ public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPersonalAppsSuspended}.
+ *
+ * @hide
+ */
+ public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setScreenCaptureDisabled}.
+ *
+ * @hide
+ */
+ public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setTrustAgentConfiguration}.
+ *
+ * @hide
+ */
+ public static final String TRUST_AGENT_CONFIGURATION_POLICY = "trustAgentConfiguration";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addCrossProfileIntentFilter}.
+ *
+ * @hide
+ */
+ public static final String CROSS_PROFILE_INTENT_FILTER_POLICY = "crossProfileIntentFilter";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addCrossProfileWidgetProvider}.
+ *
+ * @hide
+ */
+ public static final String CROSS_PROFILE_WIDGET_PROVIDER_POLICY = "crossProfileWidgetProvider";
+
+ /**
+ * @hide
+ */
+ public static final String USER_RESTRICTION_PREFIX = "userRestriction_";
+
+ /**
+ * Returns a string identifier for the provided user restrictions, see
+ * {@link DevicePolicyManager#addUserRestriction} and {@link UserManager} for the list of
+ * available restrictions.
+ */
+ @NonNull
+ public static String getIdentifierForUserRestriction(
+ @UserManager.UserRestrictionKey @NonNull String restriction) {
+ Objects.requireNonNull(restriction);
+ return USER_RESTRICTION_PREFIX + restriction;
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 409289c..ac65a6b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.SET_TIME;
@@ -3904,6 +3905,15 @@
public static final int EXEMPT_FROM_HIBERNATION = 3;
/**
+ * Exempt an app from the start foreground service from background with while in user permission
+ * restriction.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4;
+
+ /**
* Exemptions to platform restrictions, given to an application through
* {@link #setApplicationExemptions(String, Set)}.
*
@@ -3913,7 +3923,8 @@
EXEMPT_FROM_APP_STANDBY,
EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
- EXEMPT_FROM_HIBERNATION
+ EXEMPT_FROM_HIBERNATION,
+ EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationExemptionConstants {}
@@ -4029,58 +4040,6 @@
return MTE_NOT_CONTROLLED_BY_POLICY;
}
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
-
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String LOCK_TASK_POLICY = "lockTask";
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
- "userControlDisabledPackages";
-
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
- "persistentPreferredActivity";
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
-
- // TODO: Expose this as a public API
- /**
- * @hide
- */
- public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
-
/**
* This object is a single place to tack on invalidation and disable calls. All
* binder caches in this class derive from this Config, so all can be invalidated or
@@ -6900,6 +6859,11 @@
public static final int KEYGUARD_DISABLE_IRIS = 1 << 8;
/**
+ * Disable all keyguard shortcuts.
+ */
+ public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 1 << 9;
+
+ /**
* NOTE: Please remember to update the DevicePolicyManagerTest's testKeyguardDisabledFeatures
* CTS test when adding to the list above.
*/
@@ -6942,7 +6906,8 @@
*/
public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY =
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
- | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
+ | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
+ | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL;
/**
* Keyguard features that when set on a normal or organization-owned managed profile, have
@@ -8280,15 +8245,18 @@
* legacy device admins targeting SDK version {@link android.os.Build.VERSION_CODES#P} or
* below will be silently ignored.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with or null if
+ the caller is not a device admin
* @param disabled Whether or not the camera should be disabled.
* @throws SecurityException if {@code admin} is not an active administrator or does not use
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
*/
- public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
+ public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
if (mService != null) {
try {
- mService.setCameraDisabled(admin, disabled, mParentInstance);
+ mService.setCameraDisabled(admin, mContext.getPackageName(), disabled,
+ mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8759,7 +8727,8 @@
* {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS},
* {@link #KEYGUARD_DISABLE_FINGERPRINT},
* {@link #KEYGUARD_DISABLE_FACE},
- * {@link #KEYGUARD_DISABLE_IRIS}.
+ * {@link #KEYGUARD_DISABLE_IRIS},
+ * {@link #KEYGUARD_DISABLE_SHORTCUTS_ALL}.
* @throws SecurityException if {@code admin} is not an active administrator or does not user
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
*/
@@ -12586,6 +12555,33 @@
}
/**
+ * Returns whether the status bar is disabled/enabled, see {@link #setStatusBarDisabled}.
+ *
+ * <p>Callable by device owner or profile owner of secondary users that is affiliated with the
+ * device owner.
+ *
+ * <p>This policy has no effect in LockTask mode. The behavior of the
+ * status bar in LockTask mode can be configured with
+ * {@link #setLockTaskFeatures(ComponentName, int)}.
+ *
+ * <p>This policy also does not have any effect while on the lock screen, where the status bar
+ * will not be disabled.
+ *
+ * @throws SecurityException if the caller is not the device owner, or a profile owner of
+ * secondary user that is affiliated with the device.
+ * @see #isAffiliatedUser
+ * @see #getSecondaryUsers
+ */
+ public boolean isStatusBarDisabled() {
+ throwIfParentInstance("isStatusBarDisabled");
+ try {
+ return mService.isStatusBarDisabled(mContext.getPackageName());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Called by the system update service to notify device and profile owners of pending system
* updates.
*
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 11b840f..a498913 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1836,6 +1836,27 @@
*/
public static final String WORK_PROFILE_BADGED_LABEL =
PREFIX + "WORK_PROFILE_BADGED_LABEL";
+
+ /**
+ * Notification title. This notification lets the user know that they will be unable to
+ * receive phone calls or texts until the work profile is turned on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_TITLE =
+ PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_TITLE";
+
+ /**
+ * Notification text. This notification lets the user know that they will be unable to
+ * receive phone calls or texts until the work profile is turned on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_BODY =
+ PREFIX + "WORK_PROFILE_TELEPHONY_UNAVAILABLE_BODY";
+
+ /**
+ * Label for notification button. This button lets the user turn the work profile on.
+ */
+ public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON =
+ PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT";
+
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyState.java b/core/java/android/app/admin/DevicePolicyState.java
index ee33b00..6de5150 100644
--- a/core/java/android/app/admin/DevicePolicyState.java
+++ b/core/java/android/app/admin/DevicePolicyState.java
@@ -82,6 +82,11 @@
}
@Override
+ public String toString() {
+ return "DevicePolicyState { mPolicies= " + mPolicies + " }";
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/admin/DpcAuthority.java b/core/java/android/app/admin/DpcAuthority.java
index 72c16bc..cd9da9a 100644
--- a/core/java/android/app/admin/DpcAuthority.java
+++ b/core/java/android/app/admin/DpcAuthority.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -31,11 +32,18 @@
public final class DpcAuthority extends Authority {
/**
+ * Object representing a DPC authority.
+ *
* @hide
*/
+ @NonNull
+ @TestApi
public static final DpcAuthority DPC_AUTHORITY = new DpcAuthority();
- private DpcAuthority() {}
+ /**
+ * Creates an authority that represents a DPC admin.
+ */
+ public DpcAuthority() {}
@Override
public String toString() {
@@ -44,12 +52,13 @@
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -65,7 +74,7 @@
new Creator<DpcAuthority>() {
@Override
public DpcAuthority createFromParcel(Parcel source) {
- return new DpcAuthority();
+ return DPC_AUTHORITY;
}
@Override
diff --git a/core/java/android/app/admin/EnforcingAdmin.java b/core/java/android/app/admin/EnforcingAdmin.java
index 1786467..771794d 100644
--- a/core/java/android/app/admin/EnforcingAdmin.java
+++ b/core/java/android/app/admin/EnforcingAdmin.java
@@ -38,7 +38,7 @@
private final UserHandle mUserHandle;
/**
- * @hide
+ * Creates an enforcing admin with the given params.
*/
public EnforcingAdmin(
@NonNull String packageName, @NonNull Authority authority,
diff --git a/core/java/android/app/admin/FlagUnion.java b/core/java/android/app/admin/FlagUnion.java
index be924d8..599373f 100644
--- a/core/java/android/app/admin/FlagUnion.java
+++ b/core/java/android/app/admin/FlagUnion.java
@@ -22,8 +22,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Objects;
-
/**
* Class to identify a union resolution mechanism for flag policies, it's used to resolve the
* enforced policy when being set by multiple admins (see
@@ -35,8 +33,10 @@
public final class FlagUnion extends ResolutionMechanism<Integer> {
/**
- * @hide
+ * Union resolution for policies represented as int flags which resolves as the union of all
+ * flags.
*/
+ @NonNull
public static final FlagUnion FLAG_UNION = new FlagUnion();
private FlagUnion(){};
@@ -49,7 +49,7 @@
@Override
public int hashCode() {
- return Objects.hash(this);
+ return 0;
}
@Override
@@ -70,7 +70,7 @@
new Parcelable.Creator<FlagUnion>() {
@Override
public FlagUnion createFromParcel(Parcel source) {
- return new FlagUnion();
+ return FLAG_UNION;
}
@Override
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c86852a..3f66b45 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -141,7 +141,7 @@
boolean requestBugreport(in ComponentName who);
- void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent);
+ void setCameraDisabled(in ComponentName who, String callerPackageName, boolean disabled, boolean parent);
boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent);
void setScreenCaptureDisabled(in ComponentName who, boolean disabled, boolean parent);
@@ -379,6 +379,7 @@
boolean setKeyguardDisabled(in ComponentName admin, boolean disabled);
boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
+ boolean isStatusBarDisabled(in String callerPackage);
boolean getDoNotAskCredentialsOnBoot();
void notifyPendingSystemUpdate(in SystemUpdateInfo info);
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index d7eb101..f2f8aa4 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -117,7 +117,7 @@
@Override
public int hashCode() {
- return Objects.hash(getIdentifier(), mFilter);
+ return Objects.hash(getIdentifier());
}
@Override
@@ -133,7 +133,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(getIdentifier());
- mFilter.writeToParcel(dest, flags);
+ dest.writeTypedObject(mFilter, flags);
}
@NonNull
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index 28757df..f5d1cb4 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -22,7 +22,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -67,7 +66,7 @@
@Override
@NonNull
public LockTaskPolicy getValue() {
- return super.getValue();
+ return this;
}
/**
@@ -76,6 +75,7 @@
public LockTaskPolicy(@NonNull Set<String> packages) {
Objects.requireNonNull(packages);
mPackages.addAll(packages);
+ setValue(this);
}
/**
@@ -89,9 +89,13 @@
}
private LockTaskPolicy(Parcel source) {
- String[] packages = Objects.requireNonNull(source.readStringArray());
- mPackages = new HashSet<>(Arrays.stream(packages).toList());
+ int size = source.readInt();
+ mPackages = new HashSet<>();
+ for (int i = 0; i < size; i++) {
+ mPackages.add(source.readString());
+ }
mFlags = source.readInt();
+ setValue(this);
}
/**
@@ -100,6 +104,7 @@
public LockTaskPolicy(LockTaskPolicy policy) {
mPackages = new HashSet<>(policy.mPackages);
mFlags = policy.mFlags;
+ setValue(this);
}
/**
@@ -144,7 +149,10 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeArray(mPackages.toArray(new String[0]));
+ dest.writeInt(mPackages.size());
+ for (String p : mPackages) {
+ dest.writeString(p);
+ }
dest.writeInt(mFlags);
}
diff --git a/core/java/android/app/admin/MostRecent.java b/core/java/android/app/admin/MostRecent.java
index ac1657189..9df4b53 100644
--- a/core/java/android/app/admin/MostRecent.java
+++ b/core/java/android/app/admin/MostRecent.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,23 @@
@TestApi
public final class MostRecent<V> extends ResolutionMechanism<V> {
+ /**
+ * Indicates that the most recent setter of the policy wins the resolution.
+ */
+ @NonNull
+ public static final MostRecent<?> MOST_RECENT = new MostRecent<>();
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
@Override
public String toString() {
return "MostRecent {}";
@@ -46,15 +64,15 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {}
@NonNull
- public static final Parcelable.Creator<MostRecent> CREATOR =
- new Parcelable.Creator<MostRecent>() {
+ public static final Parcelable.Creator<MostRecent<?>> CREATOR =
+ new Parcelable.Creator<MostRecent<?>>() {
@Override
- public MostRecent createFromParcel(Parcel source) {
- return new MostRecent();
+ public MostRecent<?> createFromParcel(Parcel source) {
+ return new MostRecent<>();
}
@Override
- public MostRecent[] newArray(int size) {
+ public MostRecent<?>[] newArray(int size) {
return new MostRecent[size];
}
};
diff --git a/core/java/android/app/admin/MostRestrictive.java b/core/java/android/app/admin/MostRestrictive.java
index adb4744..bbe6eb2 100644
--- a/core/java/android/app/admin/MostRestrictive.java
+++ b/core/java/android/app/admin/MostRestrictive.java
@@ -47,7 +47,8 @@
/**
* Returns an ordered list of most to least restrictive values for a certain policy.
*/
- List<V> getMostToLeastRestrictiveValues() {
+ @NonNull
+ public List<V> getMostToLeastRestrictiveValues() {
return mMostToLeastRestrictive.stream().map(PolicyValue::getValue).toList();
}
@@ -55,13 +56,17 @@
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- MostRestrictive other = (MostRestrictive) o;
- return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+ try {
+ MostRestrictive<V> other = (MostRestrictive<V>) o;
+ return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+ } catch (ClassCastException exception) {
+ return false;
+ }
}
@Override
public int hashCode() {
- return Objects.hash(mMostToLeastRestrictive);
+ return mMostToLeastRestrictive.hashCode();
}
/**
diff --git a/core/java/android/app/admin/PolicyKey.java b/core/java/android/app/admin/PolicyKey.java
index a35f634..84cc66b 100644
--- a/core/java/android/app/admin/PolicyKey.java
+++ b/core/java/android/app/admin/PolicyKey.java
@@ -39,8 +39,7 @@
*
* @hide
*/
-// This is ok as the constructor is hidden and all subclasses have implemented
-// Parcelable.
+// This is ok as the constructor is hidden and all subclasses have implemented Parcelable.
@SuppressLint({"ParcelNotFinal", "ParcelCreator"})
@SystemApi
public abstract class PolicyKey implements Parcelable {
diff --git a/core/java/android/app/admin/PolicyState.java b/core/java/android/app/admin/PolicyState.java
index da71bb1..fa76bfa 100644
--- a/core/java/android/app/admin/PolicyState.java
+++ b/core/java/android/app/admin/PolicyState.java
@@ -66,7 +66,7 @@
PolicyValue<V> policyValue = source.readParcelable(PolicyValue.class.getClassLoader());
mPoliciesSetByAdmins.put(admin, policyValue);
}
- mCurrentResolvedPolicy = source.readParcelable((PolicyValue.class.getClassLoader()));
+ mCurrentResolvedPolicy = source.readParcelable(PolicyValue.class.getClassLoader());
mResolutionMechanism = source.readParcelable(ResolutionMechanism.class.getClassLoader());
}
@@ -87,7 +87,7 @@
*/
@Nullable
public V getCurrentResolvedPolicy() {
- return mCurrentResolvedPolicy.getValue();
+ return mCurrentResolvedPolicy == null ? null : mCurrentResolvedPolicy.getValue();
}
/**
diff --git a/core/java/android/app/admin/PolicyUpdateResult.java b/core/java/android/app/admin/PolicyUpdateResult.java
index a6d0ebf..79a76f2 100644
--- a/core/java/android/app/admin/PolicyUpdateResult.java
+++ b/core/java/android/app/admin/PolicyUpdateResult.java
@@ -44,6 +44,9 @@
/**
* Result code to indicate that the policy has not been enforced or has changed because another
* admin has set a conflicting policy on the device.
+ *
+ * <p>The system will automatically try to enforce the policy when it can without additional
+ * calls from the admin.
*/
public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1;
@@ -56,6 +59,22 @@
public static final int RESULT_POLICY_CLEARED = 2;
/**
+ * Result code to indicate that the policy set by the admin has not been enforced because the
+ * local storage has reached its max limit.
+ *
+ * <p>The system will NOT try to automatically store and enforce this policy again.
+ */
+ public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3;
+
+ /**
+ * Result code to indicate that the policy set by the admin has not been enforced because of a
+ * permanent hardware limitation/issue.
+ *
+ * <p>The system will NOT try to automatically store and enforce this policy again.
+ */
+ public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4;
+
+ /**
* Reason codes for {@link #getResultCode()}.
*
* @hide
@@ -65,7 +84,9 @@
RESULT_FAILURE_UNKNOWN,
RESULT_SUCCESS,
RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
- RESULT_POLICY_CLEARED
+ RESULT_POLICY_CLEARED,
+ RESULT_FAILURE_STORAGE_LIMIT_REACHED,
+ RESULT_FAILURE_HARDWARE_LIMITATION
})
public @interface ResultCode {}
diff --git a/core/java/android/app/admin/PolicyUpdatesReceiver.java b/core/java/android/app/admin/PolicyUpdatesReceiver.java
index 67de04c..be32d83 100644
--- a/core/java/android/app/admin/PolicyUpdatesReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdatesReceiver.java
@@ -104,6 +104,14 @@
"android.app.admin.extra.INTENT_FILTER";
/**
+ * A string extra holding the account type this policy applies to, (see
+ * {@link PolicyUpdatesReceiver#onPolicyChanged} and
+ * {@link PolicyUpdatesReceiver#onPolicySetResult})
+ */
+ public static final String EXTRA_ACCOUNT_TYPE =
+ "android.app.admin.extra.ACCOUNT_TYPE";
+
+ /**
* @hide
*/
public static final String EXTRA_POLICY_CHANGED_KEY =
@@ -214,7 +222,7 @@
* send updates.
*
* @param context the running context as per {@link #onReceive}
- * @param policyKey Key to identify which policy this callback relates to.
+ * @param policyIdentifier Key to identify which policy this callback relates to.
* @param additionalPolicyParams Bundle containing additional params that may be required to
* identify some of the policy
* (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -230,7 +238,7 @@
*/
public void onPolicySetResult(
@NonNull Context context,
- @NonNull String policyKey,
+ @NonNull String policyIdentifier,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
@NonNull PolicyUpdateResult policyUpdateResult) {}
@@ -247,7 +255,7 @@
* send updates.
*
* @param context the running context as per {@link #onReceive}
- * @param policyKey Key to identify which policy this callback relates to.
+ * @param policyIdentifier Key to identify which policy this callback relates to.
* @param additionalPolicyParams Bundle containing additional params that may be required to
* identify some of the policy
* (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -264,7 +272,7 @@
*/
public void onPolicyChanged(
@NonNull Context context,
- @NonNull String policyKey,
+ @NonNull String policyIdentifier,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
@NonNull PolicyUpdateResult policyUpdateResult) {}
diff --git a/core/java/android/app/admin/RoleAuthority.java b/core/java/android/app/admin/RoleAuthority.java
index 7fdd118..ccb41c3 100644
--- a/core/java/android/app/admin/RoleAuthority.java
+++ b/core/java/android/app/admin/RoleAuthority.java
@@ -22,7 +22,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -38,15 +37,18 @@
private final Set<String> mRoles;
/**
- * @hide
+ * Constructor for a role authority that accepts the list of roles held by the admin.
*/
public RoleAuthority(@NonNull Set<String> roles) {
mRoles = new HashSet<>(Objects.requireNonNull(roles));
}
private RoleAuthority(Parcel source) {
- String[] roles = source.readStringArray();
- mRoles = roles == null ? new HashSet<>() : new HashSet<>(Arrays.stream(roles).toList());
+ mRoles = new HashSet<>();
+ int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ mRoles.add(source.readString());
+ }
}
/**
@@ -64,7 +66,10 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeArray(mRoles.toArray());
+ dest.writeInt(mRoles.size());
+ for (String role : mRoles) {
+ dest.writeString(role);
+ }
}
@Override
diff --git a/core/java/android/app/admin/StringSetUnion.java b/core/java/android/app/admin/StringSetUnion.java
index 730e6a2..a95b51e 100644
--- a/core/java/android/app/admin/StringSetUnion.java
+++ b/core/java/android/app/admin/StringSetUnion.java
@@ -17,6 +17,7 @@
package android.app.admin;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +34,23 @@
@TestApi
public final class StringSetUnion extends ResolutionMechanism<Set<String>> {
+ /**
+ * Union resolution for policies represented {@code Set<String>} which resolves as the union of
+ * all sets.
+ */
+ @NonNull
+ public static final StringSetUnion STRING_SET_UNION = new StringSetUnion();
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
+ }
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
@Override
public String toString() {
return "StringSetUnion {}";
diff --git a/core/java/android/app/admin/TopPriority.java b/core/java/android/app/admin/TopPriority.java
index e712274..edb93b2 100644
--- a/core/java/android/app/admin/TopPriority.java
+++ b/core/java/android/app/admin/TopPriority.java
@@ -17,11 +17,12 @@
package android.app.admin;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -36,26 +37,56 @@
@TestApi
public final class TopPriority<V> extends ResolutionMechanism<V> {
- private final List<String> mHighestToLowestPriorityAuthorities;
+ private final List<Authority> mHighestToLowestPriorityAuthorities;
/**
* @hide
*/
- public TopPriority(@NonNull List<String> highestToLowestPriorityAuthorities) {
+ public TopPriority(@NonNull List<Authority> highestToLowestPriorityAuthorities) {
mHighestToLowestPriorityAuthorities = Objects.requireNonNull(
highestToLowestPriorityAuthorities);
}
/**
+ * Returns an object with the specified order of highest to lowest authorities.
+ */
+ private TopPriority(@NonNull Parcel source) {
+ mHighestToLowestPriorityAuthorities = new ArrayList<>();
+ int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ mHighestToLowestPriorityAuthorities.add(
+ source.readParcelable(Authority.class.getClassLoader()));
+ }
+ }
+
+ /**
* Returns an ordered list of authorities from highest priority to lowest priority for a
* certain policy.
*/
@NonNull
- List<String> getHighestToLowestPriorityAuthorities() {
+ public List<Authority> getHighestToLowestPriorityAuthorities() {
return mHighestToLowestPriorityAuthorities;
}
@Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ try {
+ TopPriority<V> other = (TopPriority<V>) o;
+ return Objects.equals(
+ mHighestToLowestPriorityAuthorities, other.mHighestToLowestPriorityAuthorities);
+ } catch (ClassCastException exception) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return mHighestToLowestPriorityAuthorities.hashCode();
+ }
+
+ @Override
public String toString() {
return "TopPriority { mHighestToLowestPriorityAuthorities= "
+ mHighestToLowestPriorityAuthorities + " }";
@@ -67,7 +98,10 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStringArray(mHighestToLowestPriorityAuthorities.toArray(new String[0]));
+ dest.writeInt(mHighestToLowestPriorityAuthorities.size());
+ for (Authority authority : mHighestToLowestPriorityAuthorities) {
+ dest.writeParcelable(authority, flags);
+ }
}
@NonNull
@@ -75,9 +109,7 @@
new Parcelable.Creator<TopPriority<?>>() {
@Override
public TopPriority<?> createFromParcel(Parcel source) {
- String[] highestToLowestPriorityAuthorities = source.readStringArray();
- return new TopPriority<>(
- Arrays.stream(highestToLowestPriorityAuthorities).toList());
+ return new TopPriority<>(source);
}
@Override
diff --git a/core/java/android/app/admin/UnknownAuthority.java b/core/java/android/app/admin/UnknownAuthority.java
index 4492b96..fdad898 100644
--- a/core/java/android/app/admin/UnknownAuthority.java
+++ b/core/java/android/app/admin/UnknownAuthority.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -32,11 +33,19 @@
public final class UnknownAuthority extends Authority {
/**
+ * Object representing an unknown authority.
+ *
* @hide
*/
+ @TestApi
+ @NonNull
public static final UnknownAuthority UNKNOWN_AUTHORITY = new UnknownAuthority();
- private UnknownAuthority() {}
+ /**
+ * Creates an authority that represents an admin that can set a policy but
+ * doesn't have a known authority (e.g. a system components).
+ */
+ public UnknownAuthority() {}
@Override
public String toString() {
@@ -45,12 +54,13 @@
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -66,7 +76,7 @@
new Creator<UnknownAuthority>() {
@Override
public UnknownAuthority createFromParcel(Parcel source) {
- return new UnknownAuthority();
+ return UNKNOWN_AUTHORITY;
}
@Override
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ffe73d6..7be00a0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -679,8 +679,9 @@
public static final int PRIVATE_FLAG_PROFILEABLE_BY_SHELL = 1 << 23;
/**
- * Indicates whether this package requires access to non-SDK APIs.
- * Only system apps and tests are allowed to use this property.
+ * Indicates whether this application has declared its user data as fragile,
+ * causing the system to prompt the user on whether to keep the user data
+ * on uninstall.
* @hide
*/
public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8f864f4..cfd291f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,8 +30,6 @@
import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
-import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.CurrentTimeMillisLong;
@@ -84,7 +82,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ExceptionUtils;
-import android.util.Log;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.util.ArrayUtils;
@@ -92,7 +89,6 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.modules.utils.TypedXmlSerializer;
import java.io.Closeable;
import java.io.File;
@@ -2313,11 +2309,6 @@
private final ArrayMap<String, Integer> mPermissionStates;
/**
- * @see #getFinalPermissionStates()
- */
- private ArrayMap<String, Integer> mFinalPermissionStates;
-
- /**
* Construct parameters for a new package install session.
*
* @param mode one of {@link #MODE_FULL_INSTALL} or
@@ -2563,11 +2554,6 @@
+ (permissionName == null ? "null" : "empty"));
}
- if (mFinalPermissionStates != null) {
- Log.wtf(TAG, "Requested permission " + permissionName + " but final permissions"
- + " were already decided for this session: " + mFinalPermissionStates);
- }
-
switch (state) {
case PERMISSION_STATE_DEFAULT:
mPermissionStates.remove(permissionName);
@@ -3008,48 +2994,10 @@
}
}
- /**
- * This is only for use by system server. If you need the actual grant state, use
- * {@link #getFinalPermissionStates()}.
- * <p/>
- * This is implemented here to avoid exposing the raw permission sets to external callers,
- * so that enforcement done in the either of the final methods is the single source of truth
- * for default grant/deny policy.
- *
- * @hide
- */
- public void writePermissionStateXml(@NonNull TypedXmlSerializer out,
- @NonNull String grantTag, @NonNull String denyTag, @NonNull String attrName)
- throws IOException {
- for (int index = 0; index < mPermissionStates.size(); index++) {
- var permissionName = mPermissionStates.keyAt(index);
- var state = mPermissionStates.valueAt(index);
- String tag = state == PERMISSION_STATE_GRANTED ? grantTag : denyTag;
- out.startTag(null, tag);
- writeStringAttribute(out, attrName, permissionName);
- out.endTag(null, tag);
- }
- }
-
- /**
- * Snapshot of final permission states taken when this method is first called, to separate
- * what the caller wanted and the effective state that should be applied to the session.
- *
- * This prevents someone from adding more permissions after the fact.
- *
- * @hide
- */
+ /** @hide */
@NonNull
- public ArrayMap<String, Integer> getFinalPermissionStates() {
- if (mFinalPermissionStates == null) {
- mFinalPermissionStates = new ArrayMap<>(mPermissionStates);
- if (!mFinalPermissionStates.containsKey(
- Manifest.permission.USE_FULL_SCREEN_INTENT)) {
- mFinalPermissionStates.put(Manifest.permission.USE_FULL_SCREEN_INTENT,
- PERMISSION_STATE_GRANTED);
- }
- }
- return mFinalPermissionStates;
+ public ArrayMap<String, Integer> getPermissionStates() {
+ return mPermissionStates;
}
/** @hide */
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7164dc3..17e81e5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1429,6 +1429,7 @@
* hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}.
*
* @see #getHdrConversionMode
+ * @see #getHdrConversionModeSetting
* @see #getSupportedHdrOutputTypes
* @hide
*/
@@ -1440,9 +1441,14 @@
/**
* Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+ * The HDR conversion mode chosen by user which considers the app override is returned. Apps can
+ * override HDR conversion using
+ * {@link android.view.WindowManager.LayoutParams#disableHdrConversion}.
*
* @see #setHdrConversionMode
* @see #getSupportedHdrOutputTypes
+ * @see #getHdrConversionModeSetting()
* @hide
*/
@TestApi
@@ -1452,6 +1458,23 @@
}
/**
+ * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+ * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+ * is disabled by an app.
+ *
+ * @see #setHdrConversionMode
+ * @see #getSupportedHdrOutputTypes
+ * @see #getHdrConversionMode()
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ public HdrConversionMode getHdrConversionModeSetting() {
+ return mGlobal.getHdrConversionModeSetting();
+ }
+
+ /**
* Returns the HDR output types supported by the device.
*
* @see #getHdrConversionMode
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index d9db177..4a992f3 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -990,6 +990,19 @@
}
/**
+ * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+ * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+ * is disabled by an app.
+ */
+ public HdrConversionMode getHdrConversionModeSetting() {
+ try {
+ return mDm.getHdrConversionModeSetting();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the {@link HdrConversionMode} of the device.
*/
public HdrConversionMode getHdrConversionMode() {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 2bd0606..d6df033 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -234,13 +234,14 @@
* @param requestedMinimalPostProcessing The preferred minimal post processing setting for the
* display. This is true when there is at least one visible window that wants minimal post
* processng on.
+ * @param disableHdrConversion The preferred HDR conversion setting for the window.
* @param inTraversal True if called from WindowManagerService during a window traversal
* prior to call to performTraversalInTransactionFromWindowManager.
*/
public abstract void setDisplayProperties(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
- boolean inTraversal);
+ boolean disableHdrConversion, boolean inTraversal);
/**
* Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 0a44f85..a3b7b51 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -180,6 +180,7 @@
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MODIFY_HDR_CONVERSION_MODE)")
void setHdrConversionMode(in HdrConversionMode hdrConversionMode);
+ HdrConversionMode getHdrConversionModeSetting();
HdrConversionMode getHdrConversionMode();
int[] getSupportedHdrOutputTypes();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13d54ef..c021cad 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2968,15 +2968,13 @@
"android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
/**
- * Intent that is broadcast when Low Power Standby is enabled or disabled.
+ * Intent that is broadcast when Low Power Standby policy is changed.
* This broadcast is only sent to registered receivers.
*
- * @see #getLowPowerStandbyPolicy
- * @see #setLowPowerStandbyPolicy
- * @hide
+ * @see #isExemptFromLowPowerStandby()
+ * @see #isAllowedInLowPowerStandby(int)
+ * @see #isAllowedInLowPowerStandby(String)
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY)
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED =
"android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
index ad3ad7a..cc64c45 100644
--- a/core/java/android/speech/IRecognitionService.aidl
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -67,12 +67,15 @@
* given recognizerIntent. For more information see {@link #startListening} and
* {@link RecognizerIntent}.
*/
- void checkRecognitionSupport(in Intent recognizerIntent, in IRecognitionSupportCallback listener);
+ void checkRecognitionSupport(
+ in Intent recognizerIntent,
+ in AttributionSource attributionSource,
+ in IRecognitionSupportCallback listener);
/**
* Requests RecognitionService to download the support for the given recognizerIntent. For more
* information see {@link #checkRecognitionSupport}, {@link #startListening} and
* {@link RecognizerIntent}.
*/
- void triggerModelDownload(in Intent recognizerIntent);
+ void triggerModelDownload(in Intent recognizerIntent, in AttributionSource attributionSource);
}
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index a5dbdd7..0b0b3b56 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -110,13 +110,14 @@
dispatchClearCallback((IRecognitionListener) msg.obj);
break;
case MSG_CHECK_RECOGNITION_SUPPORT:
- Pair<Intent, IRecognitionSupportCallback> intentAndListener =
- (Pair<Intent, IRecognitionSupportCallback>) msg.obj;
+ CheckRecognitionSupportArgs checkArgs = (CheckRecognitionSupportArgs) msg.obj;
dispatchCheckRecognitionSupport(
- intentAndListener.first, intentAndListener.second);
+ checkArgs.mIntent, checkArgs.callback, checkArgs.mAttributionSource);
break;
case MSG_TRIGGER_MODEL_DOWNLOAD:
- dispatchTriggerModelDownload((Intent) msg.obj);
+ Pair<Intent, AttributionSource> params =
+ (Pair<Intent, AttributionSource>) msg.obj;
+ dispatchTriggerModelDownload(params.first, params.second);
break;
}
}
@@ -211,12 +212,18 @@
}
private void dispatchCheckRecognitionSupport(
- Intent intent, IRecognitionSupportCallback callback) {
- RecognitionService.this.onCheckRecognitionSupport(intent, new SupportCallback(callback));
+ Intent intent, IRecognitionSupportCallback callback,
+ AttributionSource attributionSource) {
+ RecognitionService.this.onCheckRecognitionSupport(
+ intent,
+ attributionSource,
+ new SupportCallback(callback));
}
- private void dispatchTriggerModelDownload(Intent intent) {
- RecognitionService.this.onTriggerModelDownload(intent);
+ private void dispatchTriggerModelDownload(
+ Intent intent,
+ AttributionSource attributionSource) {
+ RecognitionService.this.onTriggerModelDownload(intent, attributionSource);
}
private static class StartListeningArgs {
@@ -233,6 +240,21 @@
}
}
+ private static class CheckRecognitionSupportArgs {
+ public final Intent mIntent;
+ public final IRecognitionSupportCallback callback;
+ public final AttributionSource mAttributionSource;
+
+ private CheckRecognitionSupportArgs(
+ Intent intent,
+ IRecognitionSupportCallback callback,
+ AttributionSource attributionSource) {
+ this.mIntent = intent;
+ this.callback = callback;
+ this.mAttributionSource = attributionSource;
+ }
+ }
+
/**
* Notifies the service that it should start listening for speech.
*
@@ -298,6 +320,26 @@
}
/**
+ * Queries the service on whether it would support a {@link #onStartListening(Intent, Callback)}
+ * for the same {@code recognizerIntent}.
+ *
+ * <p>The service will notify the caller about the level of support or error via
+ * {@link SupportCallback}.
+ *
+ * <p>If the service does not offer the support check it will notify the caller with
+ * {@link SpeechRecognizer#ERROR_CANNOT_CHECK_SUPPORT}.
+ *
+ * <p>Provides the calling AttributionSource to the service implementation so that permissions
+ * and bandwidth could be correctly blamed.</p>
+ */
+ public void onCheckRecognitionSupport(
+ @NonNull Intent recognizerIntent,
+ @NonNull AttributionSource attributionSource,
+ @NonNull SupportCallback supportCallback) {
+ onCheckRecognitionSupport(recognizerIntent, supportCallback);
+ }
+
+ /**
* Requests the download of the recognizer support for {@code recognizerIntent}.
*/
public void onTriggerModelDownload(@NonNull Intent recognizerIntent) {
@@ -306,6 +348,18 @@
}
}
+ /**
+ * Requests the download of the recognizer support for {@code recognizerIntent}.
+ *
+ * <p>Provides the calling AttributionSource to the service implementation so that permissions
+ * and bandwidth could be correctly blamed.</p>
+ */
+ public void onTriggerModelDownload(
+ @NonNull Intent recognizerIntent,
+ @NonNull AttributionSource attributionSource) {
+ onTriggerModelDownload(recognizerIntent);
+ }
+
@Override
@SuppressLint("MissingNullability")
public Context createContext(@NonNull ContextParams contextParams) {
@@ -524,7 +578,8 @@
public static class SupportCallback {
private final IRecognitionSupportCallback mCallback;
- private SupportCallback(IRecognitionSupportCallback callback) {
+ private SupportCallback(
+ IRecognitionSupportCallback callback) {
this.mCallback = callback;
}
@@ -596,22 +651,27 @@
@Override
public void checkRecognitionSupport(
- Intent recognizerIntent, IRecognitionSupportCallback callback) {
+ Intent recognizerIntent,
+ @NonNull AttributionSource attributionSource,
+ IRecognitionSupportCallback callback) {
final RecognitionService service = mServiceRef.get();
if (service != null) {
service.mHandler.sendMessage(
Message.obtain(service.mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
- Pair.create(recognizerIntent, callback)));
+ new CheckRecognitionSupportArgs(
+ recognizerIntent, callback, attributionSource)));
}
}
@Override
- public void triggerModelDownload(Intent recognizerIntent) {
+ public void triggerModelDownload(
+ Intent recognizerIntent, @NonNull AttributionSource attributionSource) {
final RecognitionService service = mServiceRef.get();
if (service != null) {
service.mHandler.sendMessage(
Message.obtain(
- service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, recognizerIntent));
+ service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
+ Pair.create(recognizerIntent, attributionSource)));
}
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 33c5b5a..9c46e55 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -663,6 +663,7 @@
try {
mService.checkRecognitionSupport(
recognizerIntent,
+ mContext.getAttributionSource(),
new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
if (DBG) Log.d(TAG, "service support command succeeded");
} catch (final RemoteException e) {
@@ -676,7 +677,7 @@
return;
}
try {
- mService.triggerModelDownload(recognizerIntent);
+ mService.triggerModelDownload(recognizerIntent, mContext.getAttributionSource());
} catch (final RemoteException e) {
Log.e(TAG, "downloadModel() failed", e);
mListener.onError(ERROR_CLIENT);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 680e8f7..a746dc6 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -96,12 +96,6 @@
public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui";
/**
- * Enable new shortcut list UI
- * @hide
- */
- public static final String SETTINGS_NEW_KEYBOARD_SHORTCUT = "settings_new_keyboard_shortcut";
-
- /**
* Enable new modifier key settings UI
* @hide
*/
@@ -227,7 +221,6 @@
DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true");
DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false");
- DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_SHORTCUT, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false");
@@ -255,7 +248,6 @@
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_UI);
- PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_SHORTCUT);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 61582cd..1a5613e 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1351,7 +1351,7 @@
private int mDeviceId;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mSource;
- private int mDisplayId;
+ private int mDisplayId = INVALID_DISPLAY;
private @Nullable byte[] mHmac;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int mMetaState;
@@ -1602,7 +1602,6 @@
mScanCode = scancode;
mFlags = flags;
mSource = source;
- mDisplayId = INVALID_DISPLAY;
}
/**
@@ -1628,7 +1627,6 @@
mDeviceId = deviceId;
mFlags = flags;
mSource = InputDevice.SOURCE_KEYBOARD;
- mDisplayId = INVALID_DISPLAY;
}
/**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 85365b3..a3c0d7e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -742,13 +742,6 @@
*/
public static final int POWER_MODE_ON_SUSPEND = 4;
- /**
- * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
- */
- private static final int INTERNAL_DATASPACE_SRGB = 142671872;
- private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
- private static final int INTERNAL_DATASPACE_SCRGB = 411107328;
-
private void assignNativeObject(long nativeObject, String callsite) {
if (mNativeObject != 0) {
release();
@@ -2195,18 +2188,9 @@
ColorSpace[] colorSpaces = { srgb, srgb };
if (dataspaces.length == 2) {
for (int i = 0; i < 2; ++i) {
- switch(dataspaces[i]) {
- case INTERNAL_DATASPACE_DISPLAY_P3:
- colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
- break;
- case INTERNAL_DATASPACE_SCRGB:
- colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
- break;
- case INTERNAL_DATASPACE_SRGB:
- // Other dataspace is not recognized, use SRGB color space instead,
- // the default value of the array is already SRGB, thus do nothing.
- default:
- break;
+ ColorSpace cs = ColorSpace.getFromDataSpace(dataspaces[i]);
+ if (cs != null) {
+ colorSpaces[i] = cs;
}
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d0f095c..480abe0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3741,7 +3741,7 @@
}
if (mAttachInfo.mContentCaptureEvents != null) {
- notifyContentCatpureEvents();
+ notifyContentCaptureEvents();
}
mIsInTraversal = false;
@@ -3782,7 +3782,7 @@
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
- private void notifyContentCatpureEvents() {
+ private void notifyContentCaptureEvents() {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
try {
MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0f68cd0..82b390e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3569,6 +3569,22 @@
*/
public float preferredMaxDisplayRefreshRate;
+ /** Indicates whether this window wants the HDR conversion is disabled. */
+ public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION = 1 << 0;
+
+ /**
+ * Flags that can be used to set display properties.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "DISPLAY_FLAG_", value = {
+ DISPLAY_FLAG_DISABLE_HDR_CONVERSION,
+ })
+ public @interface DisplayFlags {}
+
+ @DisplayFlags
+ private int mDisplayFlags;
+
/**
* An internal annotation for flags that can be specified to {@link #systemUiVisibility}
* and {@link #subtreeSystemUiVisibility}.
@@ -4286,6 +4302,24 @@
preservePreviousSurfaceInsets = preservePrevious;
}
+ /** Returns whether the HDR conversion is enabled for the window */
+ public boolean isHdrConversionEnabled() {
+ return ((mDisplayFlags & DISPLAY_FLAG_DISABLE_HDR_CONVERSION) == 0);
+ }
+
+ /**
+ * Enables/disables the HDR conversion for the window.
+ *
+ * By default, the HDR conversion is enabled for the window.
+ */
+ public void setHdrConversionEnabled(boolean enabled) {
+ if (!enabled) {
+ mDisplayFlags |= DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+ } else {
+ mDisplayFlags &= ~DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+ }
+ }
+
/**
* <p>Set the color mode of the window. Setting the color mode might
* override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
@@ -4460,6 +4494,7 @@
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
checkNonRecursiveParams();
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
+ out.writeInt(mDisplayFlags);
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4530,6 +4565,7 @@
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
+ mDisplayFlags = in.readInt();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4565,6 +4601,8 @@
/** {@hide} */
public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
/** {@hide} */
+ public static final int DISPLAY_FLAGS_CHANGED = 1 << 22;
+ /** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
@@ -4724,6 +4762,11 @@
changes |= PREFERRED_MAX_DISPLAY_REFRESH_RATE;
}
+ if (mDisplayFlags != o.mDisplayFlags) {
+ mDisplayFlags = o.mDisplayFlags;
+ changes |= DISPLAY_FLAGS_CHANGED;
+ }
+
if (systemUiVisibility != o.systemUiVisibility
|| subtreeSystemUiVisibility != o.subtreeSystemUiVisibility) {
systemUiVisibility = o.systemUiVisibility;
@@ -4979,6 +5022,10 @@
sb.append(" preferredMaxDisplayRefreshRate=");
sb.append(preferredMaxDisplayRefreshRate);
}
+ if (mDisplayFlags != 0) {
+ sb.append(" displayFlags=0x");
+ sb.append(Integer.toHexString(mDisplayFlags));
+ }
if (hasSystemUiListeners) {
sb.append(" sysuil=");
sb.append(hasSystemUiListeners);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e87cd12..d1c4201 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -168,6 +168,9 @@
private static final String TAG = "Editor";
private static final boolean DEBUG_UNDO = false;
+ // TODO(nona): Make this configurable.
+ private static final boolean FLAG_USE_NEW_CONTEXT_MENU = false;
+
// Specifies whether to use the magnifier when pressing the insertion or selection handles.
private static final boolean FLAG_USE_MAGNIFIER = true;
@@ -198,16 +201,6 @@
private static final int ACTION_MODE_MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
private static final int ACTION_MODE_MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
- // Ordering constants used to place the Context Menu items in their menu.
- private static final int CONTEXT_MENU_ITEM_ORDER_UNDO = 2;
- private static final int CONTEXT_MENU_ITEM_ORDER_REDO = 3;
- private static final int CONTEXT_MENU_ITEM_ORDER_CUT = 4;
- private static final int CONTEXT_MENU_ITEM_ORDER_COPY = 5;
- private static final int CONTEXT_MENU_ITEM_ORDER_PASTE = 6;
- private static final int CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 7;
- private static final int CONTEXT_MENU_ITEM_ORDER_SELECT_ALL = 8;
- private static final int CONTEXT_MENU_ITEM_ORDER_SHARE = 9;
- private static final int CONTEXT_MENU_ITEM_ORDER_AUTOFILL = 10;
private static final int CONTEXT_MENU_ITEM_ORDER_REPLACE = 11;
private static final int CONTEXT_MENU_GROUP_UNDO_REDO = Menu.FIRST;
@@ -3142,56 +3135,76 @@
}
}
- menu.setOptionalIconsVisible(true);
+ final int menuItemOrderUndo = 2;
+ final int menuItemOrderRedo = 3;
+ final int menuItemOrderCut = 4;
+ final int menuItemOrderCopy = 5;
+ final int menuItemOrderPaste = 6;
+ final int menuItemOrderPasteAsPlainText;
+ final int menuItemOrderSelectAll;
+ final int menuItemOrderShare;
+ final int menuItemOrderAutofill;
+ if (FLAG_USE_NEW_CONTEXT_MENU) {
+ menuItemOrderPasteAsPlainText = 7;
+ menuItemOrderSelectAll = 8;
+ menuItemOrderShare = 9;
+ menuItemOrderAutofill = 10;
- final int keyboard = mTextView.getResources().getConfiguration().keyboard;
- menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+ menu.setOptionalIconsVisible(true);
+ menu.setGroupDividerEnabled(true);
- menu.setGroupDividerEnabled(true);
+ final int keyboard = mTextView.getResources().getConfiguration().keyboard;
+ menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+ } else {
+ menuItemOrderShare = 7;
+ menuItemOrderSelectAll = 8;
+ menuItemOrderAutofill = 10;
+ menuItemOrderPasteAsPlainText = 11;
+ }
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, CONTEXT_MENU_ITEM_ORDER_UNDO,
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
com.android.internal.R.string.undo)
.setAlphabeticShortcut('z')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canUndo());
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, CONTEXT_MENU_ITEM_ORDER_REDO,
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
com.android.internal.R.string.redo)
.setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canRedo());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, CONTEXT_MENU_ITEM_ORDER_CUT,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
com.android.internal.R.string.cut)
.setAlphabeticShortcut('x')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canCut());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, CONTEXT_MENU_ITEM_ORDER_COPY,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
com.android.internal.R.string.copy)
.setAlphabeticShortcut('c')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canCopy());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, CONTEXT_MENU_ITEM_ORDER_PASTE,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
com.android.internal.R.string.paste)
.setAlphabeticShortcut('v')
.setEnabled(mTextView.canPaste())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
- CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT,
+ menuItemOrderPasteAsPlainText,
com.android.internal.R.string.paste_as_plain_text)
.setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
.setEnabled(mTextView.canPasteAsPlainText())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
- CONTEXT_MENU_ITEM_ORDER_SELECT_ALL, com.android.internal.R.string.selectAll)
+ menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
.setAlphabeticShortcut('a')
.setEnabled(mTextView.canSelectAllText())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, CONTEXT_MENU_ITEM_ORDER_SHARE,
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
com.android.internal.R.string.share)
.setEnabled(mTextView.canShare())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, CONTEXT_MENU_ITEM_ORDER_AUTOFILL,
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
android.R.string.autofill)
.setEnabled(mTextView.canRequestAutofill())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index e277b49..0b43eb5 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -846,6 +846,9 @@
private HardwareBuffer mThumbnail;
private int mAnimations;
private @ColorInt int mBackgroundColor;
+ // Customize activity transition animation
+ private CustomActivityTransition mCustomActivityOpenTransition;
+ private CustomActivityTransition mCustomActivityCloseTransition;
private AnimationOptions(int type) {
mType = type;
@@ -861,6 +864,15 @@
mTransitionBounds.readFromParcel(in);
mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
mAnimations = in.readInt();
+ mCustomActivityOpenTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
+ mCustomActivityCloseTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
+ }
+
+ /** Make basic customized animation for a package */
+ public static AnimationOptions makeCommonAnimOptions(String packageName) {
+ AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
+ options.mPackageName = packageName;
+ return options;
}
public static AnimationOptions makeAnimOptionsFromLayoutParameters(
@@ -871,6 +883,27 @@
return options;
}
+ /** Add customized window animations */
+ public void addOptionsFromLayoutParameters(WindowManager.LayoutParams lp) {
+ mAnimations = lp.windowAnimations;
+ }
+
+ /** Add customized activity animation attributes */
+ public void addCustomActivityTransition(boolean isOpen,
+ int enterResId, int exitResId, int backgroundColor) {
+ CustomActivityTransition customTransition = isOpen
+ ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
+ if (customTransition == null) {
+ customTransition = new CustomActivityTransition();
+ if (isOpen) {
+ mCustomActivityOpenTransition = customTransition;
+ } else {
+ mCustomActivityCloseTransition = customTransition;
+ }
+ }
+ customTransition.addCustomActivityTransition(enterResId, exitResId, backgroundColor);
+ }
+
public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition) {
AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
@@ -946,6 +979,11 @@
return mAnimations;
}
+ /** Return customized activity transition if existed. */
+ public CustomActivityTransition getCustomActivityTransition(boolean open) {
+ return open ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
@@ -957,6 +995,8 @@
mTransitionBounds.writeToParcel(dest, flags);
dest.writeTypedObject(mThumbnail, flags);
dest.writeInt(mAnimations);
+ dest.writeTypedObject(mCustomActivityOpenTransition, flags);
+ dest.writeTypedObject(mCustomActivityCloseTransition, flags);
}
@NonNull
@@ -997,5 +1037,68 @@
return "{ AnimationOptions type= " + typeToString(mType) + " package=" + mPackageName
+ " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}";
}
+
+ /** Customized activity transition. */
+ public static class CustomActivityTransition implements Parcelable {
+ private int mCustomEnterResId;
+ private int mCustomExitResId;
+ private int mCustomBackgroundColor;
+
+ /** Returns customize activity animation enter resource id */
+ public int getCustomEnterResId() {
+ return mCustomEnterResId;
+ }
+
+ /** Returns customize activity animation exit resource id */
+ public int getCustomExitResId() {
+ return mCustomExitResId;
+ }
+
+ /** Returns customize activity animation background color */
+ public int getCustomBackgroundColor() {
+ return mCustomBackgroundColor;
+ }
+ CustomActivityTransition() {}
+
+ CustomActivityTransition(Parcel in) {
+ mCustomEnterResId = in.readInt();
+ mCustomExitResId = in.readInt();
+ mCustomBackgroundColor = in.readInt();
+ }
+
+ /** Add customized activity animation attributes */
+ public void addCustomActivityTransition(
+ int enterResId, int exitResId, int backgroundColor) {
+ mCustomEnterResId = enterResId;
+ mCustomExitResId = exitResId;
+ mCustomBackgroundColor = backgroundColor;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCustomEnterResId);
+ dest.writeInt(mCustomExitResId);
+ dest.writeInt(mCustomBackgroundColor);
+ }
+
+ @NonNull
+ public static final Creator<CustomActivityTransition> CREATOR =
+ new Creator<CustomActivityTransition>() {
+ @Override
+ public CustomActivityTransition createFromParcel(Parcel in) {
+ return new CustomActivityTransition(in);
+ }
+
+ @Override
+ public CustomActivityTransition[] newArray(int size) {
+ return new CustomActivityTransition[size];
+ }
+ };
+ }
}
}
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index b0a4b54..8b41829 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -167,8 +167,9 @@
*/
@UnsupportedAppUsage
public String getFullNameInUiLanguage() {
+ Locale locale = mLocale.stripExtensions();
// We don't cache the UI name because the default locale keeps changing
- return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
+ return LocaleHelper.getDisplayName(locale, true /* sentence case */);
}
private String getLangScriptKey() {
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 205c5fd..d2b612a 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -73,6 +73,23 @@
mOnPropertiesChangedListener);
}
+ public void registerForCurrentUser() {
+ ContentResolver r = mContext.getContentResolver();
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
+ false, this);
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
+ false, this);
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
+ false, this);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ runnable -> mMainHandler.post(runnable),
+ mOnPropertiesChangedListener);
+ }
+
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bcb0da3..d2d87d6 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -427,7 +427,7 @@
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
} else if (err != NO_ERROR) {
- jniThrowException(env, OutOfResourcesException, NULL);
+ jniThrowException(env, OutOfResourcesException, statusToString(err).c_str());
return 0;
}
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 4d76aee..a137ea9 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,2 +1,3 @@
+per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
index 72d39bf..c6d3cda 100644
--- a/core/proto/android/server/OWNERS
+++ b/core/proto/android/server/OWNERS
@@ -1 +1,2 @@
+per-file activitymanagerservice.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 52d6f55..a4818c7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6091,6 +6091,11 @@
<permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to read restricted stats from statsd.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_RESTRICTED_STATS"
+ android:protectionLevel="internal|privileged" />
+
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
@@ -8110,7 +8115,7 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
- <service android:name="com.android.server.healthconnect.storage.AutoDeleteService"
+ <service android:name="com.android.server.healthconnect.HealthConnectDailyService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
diff --git a/core/res/res/drawable/ic_phone_disabled.xml b/core/res/res/drawable/ic_phone_disabled.xml
new file mode 100644
index 0000000..6e60912
--- /dev/null
+++ b/core/res/res/drawable/ic_phone_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M40.65,45.15 L28.9,33.45Q23.55,37.8 18.5,39.925Q13.45,42.05 8.6,42.05Q7.45,42.05 6.7,41.4Q5.95,40.75 5.95,39.75V33Q5.95,32.2 6.45,31.6Q6.95,31 7.7,30.85L13.65,29.55Q14.3,29.4 14.95,29.625Q15.6,29.85 16.1,30.4L20.85,35.3Q22.3,34.6 23.9,33.45Q25.5,32.3 26.75,31.3L3.2,7.7L5.35,5.55L42.8,43.05ZM18.1,36.75 L14.15,32.6Q14.15,32.6 14.15,32.6Q14.15,32.6 14.15,32.6L9,33.65Q9,33.65 9,33.65Q9,33.65 9,33.65V39Q9,39 9,39Q9,39 9,39Q11.25,38.9 13.65,38.3Q16.05,37.7 18.1,36.75ZM33.15,29.15 L31,27Q32.05,25.75 33.125,24.175Q34.2,22.6 35.05,21.3L30.05,16.25Q29.65,15.85 29.5,15.275Q29.35,14.7 29.5,14L30.8,7.75Q30.95,6.95 31.475,6.475Q32,6 32.7,6H39.7Q40.65,6 41.325,6.65Q42,7.3 42,8.25Q42,13.35 39.6,18.975Q37.2,24.6 33.15,29.15ZM36.45,18.45Q37.75,15.45 38.35,13.2Q38.95,10.95 38.9,9Q38.9,9 38.9,9Q38.9,9 38.9,9H33.6Q33.6,9 33.6,9Q33.6,9 33.6,9L32.45,14.45Q32.45,14.45 32.45,14.45Q32.45,14.45 32.45,14.45ZM36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45Q36.45,18.45 36.45,18.45ZM18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Q18.1,36.75 18.1,36.75Z"/>
+</vector>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 26927f8..47d771f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -556,6 +556,16 @@
<!-- Title for the button that turns work profile on. To be used in a notification
[CHAR LIMIT=NONE] -->
<string name="personal_apps_suspended_turn_profile_on">Turn on</string>
+ <!-- Notification title. This notification lets the user know that they will be unable to
+ receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=40] -->
+ <string name="work_profile_telephony_paused_title">Calls and messages are off</string>
+ <!-- Notification text. This notification lets the user know that they will be unable to
+ receive phone calls or texts until the work profile is turned on. [CHAR LIMIT=NONE] -->
+ <string name="work_profile_telephony_paused_text">You have paused work apps.
+ You won\'t receive phone calls or text messages.</string>
+ <!-- Label for notification button. This button lets the user turn the work profile on.
+ [CHAR LIMIT=15] -->
+ <string name="work_profile_telephony_paused_turn_on_button">Unpause work apps</string>
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 91d5692..dcd7a31 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1190,6 +1190,9 @@
<java-symbol type="string" name="personal_apps_suspension_soon_text" />
<java-symbol type="string" name="personal_apps_suspension_text" />
<java-symbol type="string" name="personal_apps_suspended_turn_profile_on" />
+ <java-symbol type="string" name="work_profile_telephony_paused_title" />
+ <java-symbol type="string" name="work_profile_telephony_paused_text" />
+ <java-symbol type="string" name="work_profile_telephony_paused_turn_on_button" />
<java-symbol type="string" name="notification_work_profile_content_description" />
<java-symbol type="string" name="factory_reset_warning" />
<java-symbol type="string" name="factory_reset_message" />
@@ -1410,6 +1413,7 @@
<java-symbol type="drawable" name="btn_borderless_rect" />
<java-symbol type="drawable" name="ic_phone" />
+ <java-symbol type="drawable" name="ic_phone_disabled" />
<java-symbol type="drawable" name="ic_bt_headphones_a2dp" />
<java-symbol type="drawable" name="ic_bt_headset_hfp" />
<java-symbol type="drawable" name="ic_bt_hearing_aid" />
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
index d8799cb..34ca502 100644
--- a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -17,12 +17,15 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Presubmit
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiUtils} class. */
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index c10ef00..cbf11c4 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -170,8 +170,7 @@
DEVICE_ID, SCAN_CODE, FLAGS);
assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
- DEVICE_ID, SCAN_CODE, FLAGS, /* source= */ 0, /* displayId= */ 0,
- CHARACTERS);
+ DEVICE_ID, SCAN_CODE, FLAGS, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
}
@Test
@@ -180,7 +179,7 @@
DEVICE_ID, SCAN_CODE);
assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
- DEVICE_ID, SCAN_CODE, /* flags= */ 0, /* source= */ 0, /* displayId= */ 0,
+ DEVICE_ID, SCAN_CODE, /* flags= */ 0, /* source= */ 0, INVALID_DISPLAY,
CHARACTERS);
}
@@ -190,7 +189,7 @@
assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0, /* flags= */ 0,
- /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
}
@Test
@@ -199,7 +198,7 @@
assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
/* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0,
- /* flags= */ 0, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ /* flags= */ 0, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
}
@Test
@@ -217,7 +216,7 @@
assertKeyEventFields(key, /* downTime= */ 0, /* eventTime= */ 0, ACTION, KEYCODE,
/* repeat= */ 0, /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD,
- /* scanCode= */ 0, FLAGS, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ /* scanCode= */ 0, FLAGS, /* source= */ 0, INVALID_DISPLAY, CHARACTERS);
}
private static KeyEvent createKey() {
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index f49e053..3d04937 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -29,9 +29,11 @@
"androidx.test.rules",
"frameworks-base-testutils",
"guava-android-testlib",
+ "platform-test-annotations",
"truth-prebuilt",
],
libs: ["android.test.runner"],
platform_apis: true,
certificate: "platform",
+ test_suites: ["device-tests"],
}
diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml
index 0c8da28..7376004 100644
--- a/core/tests/hdmitests/AndroidTest.xml
+++ b/core/tests/hdmitests/AndroidTest.xml
@@ -22,6 +22,9 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="HdmiCecTests.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="HdmiTests"/>
@@ -30,5 +33,6 @@
<option name="package" value="android.hardware.hdmi" />
<option name="hidden-api-checks" value="false"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ <option name="test-filter-dir" value="/data/data/android.hardware.hdmi" />
</test>
</configuration>
\ No newline at end of file
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
index 875ab38..9005afb 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
@@ -22,6 +22,8 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -31,6 +33,7 @@
import org.junit.runners.JUnit4;
/** Tests for {@link DeviceFeatures} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class DeviceFeaturesTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index e16a2f8..bb3e768 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -18,6 +18,7 @@
import android.os.Handler;
import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -34,6 +35,7 @@
/**
* Tests for {@link HdmiAudioSystemClient}
*/
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiAudioSystemClientTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
index 5f7468e..5039fe8 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
@@ -16,6 +16,8 @@
package android.hardware.hdmi;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@
import org.junit.runners.JUnit4;
/** Tests for {@link HdmiDeviceInfo} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiDeviceInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
index 2bce747..fde1122 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
@@ -16,6 +16,8 @@
package android.hardware.hdmi;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@
import org.junit.runners.JUnit4;
/** Tests for {@link HdmiPortInfo} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiPortInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
index fdc6b84..13212ce 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -26,6 +28,7 @@
/**
* Tests for {@link HdmiUtils}.
*/
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiUtilsTest {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 046373d..b1abc2a1 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1899,7 +1899,6 @@
/**
* Returns whether or not this Bitmap contains a Gainmap.
- * @hide
*/
public boolean hasGainmap() {
checkRecycled("Bitmap is recycled");
@@ -1908,7 +1907,6 @@
/**
* Returns the gainmap or null if the bitmap doesn't contain a gainmap
- * @hide
*/
public @Nullable Gainmap getGainmap() {
checkRecycled("Bitmap is recycled");
@@ -1919,6 +1917,14 @@
}
/**
+ * Sets a gainmap on this bitmap, or removes the gainmap if null
+ */
+ public void setGainmap(@Nullable Gainmap gainmap) {
+ checkRecycled("Bitmap is recycled");
+ nativeSetGainmap(mNativePtr, gainmap == null ? 0 : gainmap.mNativePtr);
+ }
+
+ /**
* Fills the bitmap's pixels with the specified {@link Color}.
*
* @throws IllegalStateException if the bitmap is not mutable.
@@ -2403,6 +2409,7 @@
private static native void nativeSetImmutable(long nativePtr);
private static native Gainmap nativeExtractGainmap(long nativePtr);
+ private static native void nativeSetGainmap(long bitmapPtr, long gainmapPtr);
// ---------------- @CriticalNative -------------------
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index a25a605..53f23c0 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import libcore.util.NativeAllocationRegistry;
@@ -24,104 +25,288 @@
* Gainmap represents a mechanism for augmenting an SDR image to produce an HDR one with variable
* display adjustment capability.
*
- * It is a combination of a set of metadata describing the gainmap, as well as either a 1 or 3
+ * It is a combination of a set of metadata describing how to apply the gainmap, as well as either
+ * a 1 (such as {@link android.graphics.Bitmap.Config#ALPHA_8} or 3
+ * (such as {@link android.graphics.Bitmap.Config#ARGB_8888} with the alpha channel ignored)
* channel Bitmap that represents the gainmap data itself.
*
- * @hide
+ * When rendering to an {@link android.content.pm.ActivityInfo#COLOR_MODE_HDR} activity, the
+ * hardware accelerated {@link Canvas} will automatically apply the gainmap when sufficient
+ * HDR headroom is available.
+ *
+ * <h3>Gainmap Structure</h3>
+ *
+ * The logical whole of a gainmap'd image consists of a base Bitmap that represents the original
+ * image as would be displayed without gainmap support in addition to a gainmap with a second
+ * enhancement image. In the case of a JPEG, the base image would be the typical 8-bit SDR image
+ * that the format is commonly associated with. The gainmap image is embedded alongside the base
+ * image, often at a lower resolution (such as 1/4th), along with some metadata to describe
+ * how to apply the gainmap. The gainmap image itself is then a greyscale image representing
+ * the transformation to apply onto the base image to reconstruct an HDR rendition of it.
+ *
+ * As such these "gainmap images" consist of 3 parts - a base {@link Bitmap} with a
+ * {@link Bitmap#getGainmap()} that returns an instance of this class which in turn contains
+ * the enhancement layer represented as another Bitmap, accessible via {@link #getGainmapContents()}
+ *
+ * <h3>Applying a gainmap manually</h3>
+ *
+ * When doing custom rendering such as to an OpenGL ES or Vulkan context, the gainmap is not
+ * automatically applied. In such situations, the following steps are appropriate to render the
+ * gainmap in combination with the base image.
+ *
+ * Suppose our display has HDR to SDR ratio of H, and we wish to display an image with gainmap on
+ * this display. Let B be the pixel value from the base image in a color space that has the
+ * primaries of the base image and a linear transfer function. Let G be the pixel value from the
+ * gainmap. Let D be the output pixel in the same color space as B. The value of D is computed
+ * as follows:
+ *
+ * First, let W be a weight parameter determining how much the gainmap will be applied.
+ * W = clamp((log(H) - log(displayRatioHdr)) /
+ * (log(displayRatioHdr) - log(displayRatioSdr), 0, 1)
+ *
+ * Next, let L be the gainmap value in log space. We compute this from the value G that was
+ * sampled from the texture as follows:
+ * L = mix(log(gainmapRatioMin), log(gainmapRatioMax), pow(G, gainmapGamma))
+ *
+ * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then
+ * compute:
+ * D = (B + epsilonSdr) * exp(L * W) - epsilonHdr
+ * If the base image is HDR then compute:
+ * D = (B + epsilonHdr) * exp(L * (W - 1)) - epsilonSdr
+ *
+ * In the above math, log() is a natural logarithm and exp() is natural exponentiation.
*/
-public class Gainmap {
- private final long mNativePtr;
- private final Bitmap mGainmapImage;
+public final class Gainmap {
- // called from JNI and Bitmap_Delegate.
- private Gainmap(Bitmap gainmapImage, long nativeGainmap, int allocationByteCount,
- boolean fromMalloc) {
+ // Use a Holder to allow static initialization of Gainmap in the boot image.
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ Gainmap.class.getClassLoader(), nGetFinalizer());
+ }
+
+ final long mNativePtr;
+ private Bitmap mGainmapContents;
+
+ // called from JNI
+ private Gainmap(Bitmap gainmapContents, long nativeGainmap) {
if (nativeGainmap == 0) {
throw new RuntimeException("internal error: native gainmap is 0");
}
- mGainmapImage = gainmapImage;
+ mGainmapContents = gainmapContents;
mNativePtr = nativeGainmap;
- final NativeAllocationRegistry registry;
- if (fromMalloc) {
- registry = NativeAllocationRegistry.createMalloced(
- Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
- } else {
- registry = NativeAllocationRegistry.createNonmalloced(
- Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
- }
- registry.registerNativeAllocation(this, nativeGainmap);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, nativeGainmap);
}
/**
- * Returns the image data of the gainmap represented as a Bitmap
- * @return
+ * Creates a gainmap from a given Bitmap. The caller is responsible for setting the various
+ * fields to the desired values. The defaults are as follows:
+ * <ul>
+ * <li>Ratio min is 1f, 1f, 1f</li>
+ * <li>Ratio max is 2f, 2f, 2f</li>
+ * <li>Gamma is 1f, 1f, 1f</li>
+ * <li>Epsilon SDR is 0f, 0f, 0f</li>
+ * <li>Epsilon HDR is 0f, 0f, 0f</li>
+ * <li>Display ratio SDR is 1f</li>
+ * <li>Display ratio HDR is 2f</li>
+ * </ul>
+ * It is strongly recommended that at least the ratio max and display ratio HDR are adjusted
+ * to better suit the given gainmap contents.
+ */
+ public Gainmap(@NonNull Bitmap gainmapContents) {
+ this(gainmapContents, nCreateEmpty());
+ }
+
+ /**
+ * @return Returns the image data of the gainmap represented as a Bitmap. This is represented
+ * as a Bitmap for broad API compatibility, however certain aspects of the Bitmap are ignored
+ * such as {@link Bitmap#getColorSpace()} or {@link Bitmap#getGainmap()} as they are not
+ * relevant to the gainmap's enhancement layer.
*/
@NonNull
- public Bitmap getGainmapImage() {
- return mGainmapImage;
+ public Bitmap getGainmapContents() {
+ return mGainmapContents;
}
/**
- * Sets the gainmap max metadata. For single-plane gainmaps, r, g, and b should be the same.
+ * Sets the image data of the gainmap. This is the 1 or 3 channel enhancement layer to apply
+ * to the base image. This is represented as a Bitmap for broad API compatibility, however
+ * certain aspects of the Bitmap are ignored such as {@link Bitmap#getColorSpace()} or
+ * {@link Bitmap#getGainmap()} as they are not relevant to the gainmap's enhancement layer.
+ *
+ * @param bitmap The non-null bitmap to set as the gainmap's contents
+ */
+ public void setGainmapContents(@NonNull Bitmap bitmap) {
+ // TODO: Validate here or leave native-side?
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Bitmap is recycled");
+ nSetBitmap(mNativePtr, bitmap);
+ mGainmapContents = bitmap;
+ }
+
+ /**
+ * Sets the gainmap ratio min. For single-plane gainmaps, r, g, and b should be the same.
*/
@NonNull
- public void setGainmapMax(float r, float g, float b) {
- nSetGainmapMax(mNativePtr, r, g, b);
+ public void setRatioMin(float r, float g, float b) {
+ nSetRatioMin(mNativePtr, r, g, b);
}
/**
- * Gets the gainmap max metadata. For single-plane gainmaps, all 3 components should be the
+ * Gets the gainmap ratio max. For single-plane gainmaps, all 3 components should be the
* same. The components are in r, g, b order.
*/
@NonNull
- public float[] getGainmapMax() {
+ public float[] getRatioMin() {
float[] ret = new float[3];
- nGetGainmapMax(mNativePtr, ret);
+ nGetRatioMin(mNativePtr, ret);
return ret;
}
/**
- * Sets the maximum HDR ratio for the gainmap
+ * Sets the gainmap ratio max. For single-plane gainmaps, r, g, and b should be the same.
*/
@NonNull
- public void setHdrRatioMax(float max) {
- nSetHdrRatioMax(mNativePtr, max);
+ public void setRatioMax(float r, float g, float b) {
+ nSetRatioMax(mNativePtr, r, g, b);
}
/**
- * Gets the maximum HDR ratio for the gainmap
+ * Gets the gainmap ratio max. For single-plane gainmaps, all 3 components should be the
+ * same. The components are in r, g, b order.
*/
@NonNull
- public float getHdrRatioMax() {
- return nGetHdrRatioMax(mNativePtr);
+ public float[] getRatioMax() {
+ float[] ret = new float[3];
+ nGetRatioMax(mNativePtr, ret);
+ return ret;
}
/**
- * Sets the maximum HDR ratio for the gainmap
+ * Sets the gainmap gamma. For single-plane gainmaps, r, g, and b should be the same.
*/
@NonNull
- public void setHdrRatioMin(float min) {
- nSetHdrRatioMin(mNativePtr, min);
+ public void setGamma(float r, float g, float b) {
+ nSetGamma(mNativePtr, r, g, b);
}
/**
- * Gets the maximum HDR ratio for the gainmap
+ * Gets the gainmap gamma. For single-plane gainmaps, all 3 components should be the
+ * same. The components are in r, g, b order.
*/
@NonNull
- public float getHdrRatioMin() {
- return nGetHdrRatioMin(mNativePtr);
+ public float[] getGamma() {
+ float[] ret = new float[3];
+ nGetGamma(mNativePtr, ret);
+ return ret;
+ }
+
+ /**
+ * Sets the sdr epsilon which is used to avoid numerical instability.
+ * For single-plane gainmaps, r, g, and b should be the same.
+ */
+ @NonNull
+ public void setEpsilonSdr(float r, float g, float b) {
+ nSetEpsilonSdr(mNativePtr, r, g, b);
+ }
+
+ /**
+ * Gets the sdr epsilon. For single-plane gainmaps, all 3 components should be the
+ * same. The components are in r, g, b order.
+ */
+ @NonNull
+ public float[] getEpsilonSdr() {
+ float[] ret = new float[3];
+ nGetEpsilonSdr(mNativePtr, ret);
+ return ret;
+ }
+
+ /**
+ * Sets the hdr epsilon which is used to avoid numerical instability.
+ * For single-plane gainmaps, r, g, and b should be the same.
+ */
+ @NonNull
+ public void setEpsilonHdr(float r, float g, float b) {
+ nSetEpsilonHdr(mNativePtr, r, g, b);
+ }
+
+ /**
+ * Gets the hdr epsilon. For single-plane gainmaps, all 3 components should be the
+ * same. The components are in r, g, b order.
+ */
+ @NonNull
+ public float[] getEpsilonHdr() {
+ float[] ret = new float[3];
+ nGetEpsilonHdr(mNativePtr, ret);
+ return ret;
+ }
+
+ /**
+ * Sets the hdr/sdr ratio at which point the gainmap is fully applied.
+ * @param max The hdr/sdr ratio at which the gainmap is fully applied. Must be >= 1.0f
+ */
+ @NonNull
+ public void setDisplayRatioForFullHdr(float max) {
+ if (!Float.isFinite(max) || max < 1f) {
+ throw new IllegalArgumentException(
+ "setDisplayRatioForFullHdr must be >= 1.0f, got = " + max);
+ }
+ nSetDisplayRatioHdr(mNativePtr, max);
+ }
+
+ /**
+ * Gets the hdr/sdr ratio at which point the gainmap is fully applied.
+ */
+ @NonNull
+ public float getDisplayRatioForFullHdr() {
+ return nGetDisplayRatioHdr(mNativePtr);
+ }
+
+ /**
+ * Sets the hdr/sdr ratio below which only the SDR image is displayed.
+ * @param min The minimum hdr/sdr ratio at which to begin applying the gainmap. Must be >= 1.0f
+ */
+ @NonNull
+ public void setMinDisplayRatioForHdrTransition(@FloatRange(from = 1.0f) float min) {
+ if (!Float.isFinite(min) || min < 1f) {
+ throw new IllegalArgumentException(
+ "setMinDisplayRatioForHdrTransition must be >= 1.0f, got = " + min);
+ }
+ nSetDisplayRatioSdr(mNativePtr, min);
+ }
+
+ /**
+ * Gets the hdr/sdr ratio below which only the SDR image is displayed.
+ */
+ @NonNull
+ public float getMinDisplayRatioForHdrTransition() {
+ return nGetDisplayRatioSdr(mNativePtr);
}
private static native long nGetFinalizer();
+ private static native long nCreateEmpty();
- private static native void nSetGainmapMax(long ptr, float r, float g, float b);
- private static native void nGetGainmapMax(long ptr, float[] components);
+ private static native void nSetBitmap(long ptr, Bitmap bitmap);
- private static native void nSetHdrRatioMax(long ptr, float max);
- private static native float nGetHdrRatioMax(long ptr);
+ private static native void nSetRatioMin(long ptr, float r, float g, float b);
+ private static native void nGetRatioMin(long ptr, float[] components);
- private static native void nSetHdrRatioMin(long ptr, float min);
- private static native float nGetHdrRatioMin(long ptr);
+ private static native void nSetRatioMax(long ptr, float r, float g, float b);
+ private static native void nGetRatioMax(long ptr, float[] components);
+
+ private static native void nSetGamma(long ptr, float r, float g, float b);
+ private static native void nGetGamma(long ptr, float[] components);
+
+ private static native void nSetEpsilonSdr(long ptr, float r, float g, float b);
+ private static native void nGetEpsilonSdr(long ptr, float[] components);
+
+ private static native void nSetEpsilonHdr(long ptr, float r, float g, float b);
+ private static native void nGetEpsilonHdr(long ptr, float[] components);
+
+ private static native void nSetDisplayRatioHdr(long ptr, float max);
+ private static native float nGetDisplayRatioHdr(long ptr);
+
+ private static native void nSetDisplayRatioSdr(long ptr, float min);
+ private static native float nGetDisplayRatioSdr(long ptr);
}
diff --git a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
index 7475aba..b2d5939 100644
--- a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
+++ b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
@@ -18,6 +18,20 @@
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
<item android:state_focused="true">
<set>
<objectAnimator
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b8e8363..d6e1a82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -25,7 +25,6 @@
import static android.util.RotationUtils.rotateBounds;
import static android.util.RotationUtils.rotateInsets;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -46,9 +45,9 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.Surface;
+import android.view.WindowInsets;
import androidx.annotation.VisibleForTesting;
@@ -372,23 +371,20 @@
// Only navigation bar
if (hasNavigationBar) {
- final InsetsSource extraNavBar = insetsState.peekSource(ITYPE_EXTRA_NAVIGATION_BAR);
- final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
+ final Insets insets = insetsState.calculateInsets(
+ insetsState.getDisplayFrame(),
+ WindowInsets.Type.navigationBars(),
+ false /* ignoreVisibility */);
+ outInsets.set(insets.left, insets.top, insets.right, insets.bottom);
int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
int navBarSize =
getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
if (position == NAV_BAR_BOTTOM) {
- outInsets.bottom = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().height())
- : navBarSize;
+ outInsets.bottom = Math.max(outInsets.bottom , navBarSize);
} else if (position == NAV_BAR_RIGHT) {
- outInsets.right = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().width())
- : navBarSize;
+ outInsets.right = Math.max(outInsets.right , navBarSize);
} else if (position == NAV_BAR_LEFT) {
- outInsets.left = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().width())
- : navBarSize;
+ outInsets.left = Math.max(outInsets.left , navBarSize);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 02b9197..a437a3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -740,7 +740,7 @@
if (mRegistered) return;
mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
- mMainHandler);
+ mMainHandler, Context.RECEIVER_NOT_EXPORTED);
mRegistered = true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 1549355..5a5ceab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -142,9 +142,12 @@
Animation a = null;
if (animAttr != 0) {
if (overrideType == ANIM_FROM_STYLE && !isTask) {
- a = transitionAnimation
- .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
- animAttr, translucent);
+ a = loadCustomActivityTransition(animAttr, options, enter, transitionAnimation);
+ if (a == null) {
+ a = transitionAnimation
+ .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+ animAttr, translucent);
+ }
} else {
a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
}
@@ -157,6 +160,37 @@
return a;
}
+ static Animation loadCustomActivityTransition(int animAttr,
+ TransitionInfo.AnimationOptions options, boolean enter,
+ TransitionAnimation transitionAnimation) {
+ Animation a = null;
+ boolean isOpen = false;
+ switch (animAttr) {
+ case R.styleable.WindowAnimation_activityOpenEnterAnimation:
+ case R.styleable.WindowAnimation_activityOpenExitAnimation:
+ isOpen = true;
+ break;
+ case R.styleable.WindowAnimation_activityCloseEnterAnimation:
+ case R.styleable.WindowAnimation_activityCloseExitAnimation:
+ break;
+ default:
+ return null;
+ }
+
+ final TransitionInfo.AnimationOptions.CustomActivityTransition transitionAnim =
+ options.getCustomActivityTransition(isOpen);
+ if (transitionAnim != null) {
+ a = transitionAnimation.loadAppTransitionAnimation(options.getPackageName(),
+ enter ? transitionAnim.getCustomEnterResId()
+ : transitionAnim.getCustomExitResId());
+ if (a != null && transitionAnim.getCustomBackgroundColor() != 0) {
+ a.setBackdropColor(transitionAnim.getCustomBackgroundColor());
+ }
+ }
+
+ return a;
+ }
+
/**
* Gets the background {@link ColorInt} for the given transition animation if it is set.
*
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 05fd889..e8784d7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -18,7 +18,6 @@
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -333,7 +332,8 @@
mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
InsetsState insetsState = new InsetsState();
- InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
+ InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
insetsSource.setFrame(0, 0, 1000, 1000);
insetsState.addSource(insetsSource);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index f3f615d9..4de5298 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -20,7 +20,6 @@
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -338,8 +337,10 @@
// Update if the insets change on the existing display layout
clearInvocations(mWindowManager);
InsetsState insetsState = new InsetsState();
- InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
- insetsSource.setFrame(0, 0, 1000, 1000);
+ insetsState.setDisplayFrame(new Rect(0, 0, 1000, 2000));
+ InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+ insetsSource.setFrame(0, 1800, 1000, 2000);
insetsState.addSource(insetsSource);
displayLayout.setInsets(mContext.getResources(), insetsState);
mWindowManager.updateDisplayLayout(displayLayout);
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 6d7c727..5bf53d0 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -506,6 +506,9 @@
decoder.mOverrideOrigin.emplace(getOrigin());
// Update mDecodeSize / mTargetSize for the overridden origin
decoder.setTargetSize(decoder.width(), decoder.height());
+ if (decoder.gray()) {
+ decoder.setOutColorType(kGray_8_SkColorType);
+ }
const bool isScaled = width() != mTargetSize.width() || height() != mTargetSize.height();
@@ -528,6 +531,9 @@
}
SkImageInfo bitmapInfo = decoder.getOutputInfo();
+ if (bitmapInfo.colorType() == kGray_8_SkColorType) {
+ bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
+ }
SkBitmap bm;
if (!bm.setInfo(bitmapInfo)) {
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 23a7520..e71a2a5 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -1300,6 +1300,13 @@
return Gainmap_extractFromBitmap(env, bitmapHolder->bitmap());
}
+static void Bitmap_setGainmap(JNIEnv*, jobject, jlong bitmapHandle, jlong gainmapPtr) {
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return;
+ uirenderer::Gainmap* gainmap = reinterpret_cast<uirenderer::Gainmap*>(gainmapPtr);
+ bitmapHolder->bitmap().setGainmap(sp<uirenderer::Gainmap>::fromExisting(gainmap));
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gBitmapMethods[] = {
@@ -1351,6 +1358,7 @@
{"nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
{"nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
{"nativeExtractGainmap", "(J)Landroid/graphics/Gainmap;", (void*)Bitmap_extractGainmap},
+ {"nativeSetGainmap", "(JJ)V", (void*)Bitmap_setGainmap},
// ------------ @CriticalNative ----------------
{"nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index f2efbc7..9cd3fb0 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -45,20 +45,18 @@
jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
auto gainmap = bitmap.gainmap();
jobject jGainmapImage;
- size_t allocationSize;
{
// Scope to guard the release of nativeBitmap
auto nativeBitmap = gainmap->bitmap;
const int createFlags = getCreateFlags(nativeBitmap);
- allocationSize = nativeBitmap->getAllocationByteCount();
jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
}
// Grab a ref for the jobject
gainmap->incStrong(0);
jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
- gainmap.get(), allocationSize + sizeof(Gainmap), true);
+ gainmap.get());
if (env->ExceptionCheck() != 0) {
// sadtrombone
@@ -77,47 +75,109 @@
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
}
-static void Gainmap_setGainmapMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
- jfloat b) {
- fromJava(gainmapPtr)->info.fLogRatioMax = {r, g, b, 1.f};
+jlong Gainmap_createEmpty(JNIEnv*, jobject) {
+ Gainmap* gainmap = new Gainmap();
+ gainmap->incStrong(0);
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
}
-static void Gainmap_getGainmapMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
- const auto ratioMax = fromJava(gainmapPtr)->info.fLogRatioMax;
- jfloat buf[3]{ratioMax.fR, ratioMax.fG, ratioMax.fB};
+static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
+ android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
+ fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
+}
+
+static void Gainmap_setRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+ fromJava(gainmapPtr)->info.fGainmapRatioMin = {r, g, b, 1.f};
+}
+
+static void Gainmap_getRatioMin(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMin;
+ jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
-static void Gainmap_setHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
- fromJava(gainmapPtr)->info.fHdrRatioMax = max;
+static void Gainmap_setRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+ fromJava(gainmapPtr)->info.fGainmapRatioMax = {r, g, b, 1.f};
}
-static jfloat Gainmap_getHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr) {
- return fromJava(gainmapPtr)->info.fHdrRatioMax;
+static void Gainmap_getRatioMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMax;
+ jfloat buf[3]{value.fR, value.fG, value.fB};
+ env->SetFloatArrayRegion(components, 0, 3, buf);
}
-static void Gainmap_setHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
- fromJava(gainmapPtr)->info.fHdrRatioMin = min;
+static void Gainmap_setGamma(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
+ fromJava(gainmapPtr)->info.fGainmapGamma = {r, g, b, 1.f};
}
-static jfloat Gainmap_getHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr) {
- return fromJava(gainmapPtr)->info.fHdrRatioMin;
+static void Gainmap_getGamma(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto value = fromJava(gainmapPtr)->info.fGainmapGamma;
+ jfloat buf[3]{value.fR, value.fG, value.fB};
+ env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setEpsilonSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
+ jfloat b) {
+ fromJava(gainmapPtr)->info.fEpsilonSdr = {r, g, b, 1.f};
+}
+
+static void Gainmap_getEpsilonSdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto value = fromJava(gainmapPtr)->info.fEpsilonSdr;
+ jfloat buf[3]{value.fR, value.fG, value.fB};
+ env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setEpsilonHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
+ jfloat b) {
+ fromJava(gainmapPtr)->info.fEpsilonHdr = {r, g, b, 1.f};
+}
+
+static void Gainmap_getEpsilonHdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto value = fromJava(gainmapPtr)->info.fEpsilonHdr;
+ jfloat buf[3]{value.fR, value.fG, value.fB};
+ env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
+ fromJava(gainmapPtr)->info.fDisplayRatioHdr = max;
+}
+
+static jfloat Gainmap_getDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr) {
+ return fromJava(gainmapPtr)->info.fDisplayRatioHdr;
+}
+
+static void Gainmap_setDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
+ fromJava(gainmapPtr)->info.fDisplayRatioSdr = min;
+}
+
+static jfloat Gainmap_getDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr) {
+ return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
}
static const JNINativeMethod gGainmapMethods[] = {
{"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
- {"nSetGainmapMax", "(JFFF)V", (void*)Gainmap_setGainmapMax},
- {"nGetGainmapMax", "(J[F)V", (void*)Gainmap_getGainmapMax},
- {"nSetHdrRatioMax", "(JF)V", (void*)Gainmap_setHdrRatioMax},
- {"nGetHdrRatioMax", "(J)F", (void*)Gainmap_getHdrRatioMax},
- {"nSetHdrRatioMin", "(JF)V", (void*)Gainmap_setHdrRatioMin},
- {"nGetHdrRatioMin", "(J)F", (void*)Gainmap_getHdrRatioMin},
+ {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
+ {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
+ {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
+ {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
+ {"nSetRatioMax", "(JFFF)V", (void*)Gainmap_setRatioMax},
+ {"nGetRatioMax", "(J[F)V", (void*)Gainmap_getRatioMax},
+ {"nSetGamma", "(JFFF)V", (void*)Gainmap_setGamma},
+ {"nGetGamma", "(J[F)V", (void*)Gainmap_getGamma},
+ {"nSetEpsilonSdr", "(JFFF)V", (void*)Gainmap_setEpsilonSdr},
+ {"nGetEpsilonSdr", "(J[F)V", (void*)Gainmap_getEpsilonSdr},
+ {"nSetEpsilonHdr", "(JFFF)V", (void*)Gainmap_setEpsilonHdr},
+ {"nGetEpsilonHdr", "(J[F)V", (void*)Gainmap_getEpsilonHdr},
+ {"nSetDisplayRatioHdr", "(JF)V", (void*)Gainmap_setDisplayRatioHdr},
+ {"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
+ {"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
+ {"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
};
int register_android_graphics_Gainmap(JNIEnv* env) {
gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
gGainmap_constructorMethodID =
- GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;JIZ)V");
+ GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;J)V");
return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
NELEM(gGainmapMethods));
}
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 80bca1f..6c070fe 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -238,7 +238,7 @@
}
///////////////////////////////////////////////////////////////////////////////
-using namespace android::recoverymap;
+using namespace android::jpegrecoverymap;
jpegr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) {
switch (aDataSpace & ADataSpace::STANDARD_MASK) {
@@ -294,7 +294,7 @@
return false;
}
- RecoveryMap recoveryMap;
+ JpegR jpegREncoder;
jpegr_uncompressed_struct p010;
p010.data = hdr;
@@ -314,7 +314,7 @@
std::unique_ptr<uint8_t[]> jpegr_data = std::make_unique<uint8_t[]>(jpegR.maxLength);
jpegR.data = jpegr_data.get();
- if (int success = recoveryMap.encodeJPEGR(&p010, &yuv420,
+ if (int success = jpegREncoder.encodeJPEGR(&p010, &yuv420,
hdrTransferFunction,
&jpegR, jpegQuality, nullptr); success != android::OK) {
ALOGW("Encode JPEG/R failed, error code: %d.", success);
diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index 3d6d1f3..d22a26c 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
@@ -2,7 +2,7 @@
#define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
#include <android/data_space.h>
-#include <jpegrecoverymap/recoverymap.h>
+#include <jpegrecoverymap/jpegr.h>
extern "C" {
#include "jpeglib.h"
@@ -77,7 +77,7 @@
class P010Yuv420ToJpegREncoder {
public:
/** Encode YUV data to jpeg/r, which is output to a stream.
- * This method will call RecoveryMap::EncodeJPEGR() method. If encoding failed,
+ * This method will call JpegR::EncodeJPEGR() method. If encoding failed,
* Corresponding error code (defined in jpegrerrorcode.h) will be printed and this
* method will be terminated and return false.
*
@@ -103,7 +103,7 @@
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::recoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
+ static android::jpegrecoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
/** Map data space (defined in DataSpace.java and data_space.h) to the transfer function
* used in JPEG/R
@@ -112,7 +112,7 @@
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::recoverymap::jpegr_transfer_function findHdrTransferFunction(
+ static android::jpegrecoverymap::jpegr_transfer_function findHdrTransferFunction(
JNIEnv* env, int aDataSpace);
};
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7de3abc3..5a03ad3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7625,22 +7625,13 @@
return codecConfigList;
}
- /**
- * Returns a list of audio formats that corresponds to encoding formats
- * supported on offload path for Le audio playback.
- *
- * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
- * supported for offload Le Audio playback
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @NonNull
- public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+ private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
+ @AudioSystem.BtOffloadDeviceType int deviceType) {
ArrayList<Integer> formatsList = new ArrayList<>();
ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
- AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
+ deviceType, formatsList);
if (status != AudioManager.SUCCESS) {
Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
return leAudioCodecConfigList;
@@ -7657,6 +7648,34 @@
return leAudioCodecConfigList;
}
+ /**
+ * Returns a list of audio formats that corresponds to encoding formats
+ * supported on offload path for Le audio playback.
+ *
+ * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+ * supported for offload Le Audio playback
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+ return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ /**
+ * Returns a list of audio formats that corresponds to encoding formats
+ * supported on offload path for Le Broadcast playback.
+ *
+ * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+ * supported for offload Le Broadcast playback
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
+ return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
+ }
+
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
// (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
// of the ports that exist at the time of the last notification.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9339c3d..293d3d2 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -273,10 +273,11 @@
/** @hide */
@IntDef(flag = false, prefix = "DEVICE_", value = {
DEVICE_OUT_BLUETOOTH_A2DP,
- DEVICE_OUT_BLE_HEADSET}
+ DEVICE_OUT_BLE_HEADSET,
+ DEVICE_OUT_BLE_BROADCAST}
)
@Retention(RetentionPolicy.SOURCE)
- public @interface DeviceType {}
+ public @interface BtOffloadDeviceType {}
/**
* @hide
@@ -1970,7 +1971,7 @@
* Returns a list of audio formats (codec) supported on the A2DP and LE audio offload path.
*/
public static native int getHwOffloadFormatsSupportedForBluetoothMedia(
- @DeviceType int deviceType, ArrayList<Integer> formatList);
+ @BtOffloadDeviceType int deviceType, ArrayList<Integer> formatList);
/** @hide */
public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index cdeef2b..9a995a0 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -78,18 +78,28 @@
*
* @param view The related {@link TvInteractiveAppView} instance that is linked to this TV
* recording client. {@code null} to unlink the view.
- * @param recordingId The ID of the recording which is assigned by applications. {@code null} is
- * valid only when the TvInteractiveAppView parameter is null.
- * @hide
+ * @param recordingId The ID of the recording which is assigned by the TV application.
+ * {@code null} if and only if the TvInteractiveAppView parameter is
+ * {@code null}.
+ * @throws IllegalArgumentException when recording ID is {@code null} and the
+ * TvInteractiveAppView is not {@code null}; or when recording
+ * ID is not {@code null} and the TvInteractiveAppView is
+ * {@code null}.
+ * @see TvInteractiveAppView#notifyRecordingScheduled(String, String)
+ * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
*/
public void setTvInteractiveAppView(
@Nullable TvInteractiveAppView view, @Nullable String recordingId) {
if (view != null && recordingId == null) {
throw new IllegalArgumentException(
- "null recordingId is allowed only when the view is null");
+ "null recordingId is not allowed only when the view is not null");
+ }
+ if (view == null && recordingId != null) {
+ throw new IllegalArgumentException(
+ "recordingId should be null when the view is null");
}
mTvIAppView = view;
- mRecordingId = view == null ? null : recordingId;
+ mRecordingId = recordingId;
}
/**
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index aac2d61..36954ad 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -51,12 +51,12 @@
void onRequestCurrentTvInputId(int seq);
void onRequestTimeShiftMode(int seq);
void onRequestAvailableSpeeds(int seq);
- void onRequestStartRecording(in Uri programUri, int seq);
+ void onRequestStartRecording(in String requestId, in Uri programUri, int seq);
void onRequestStopRecording(in String recordingId, int seq);
- void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
- in Bundle params, int seq);
- void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
- long duration, int repeat, in Bundle params, int seq);
+ void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+ in Uri programUri, in Bundle params, int seq);
+ void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+ long start, long duration, int repeat, in Bundle params, int seq);
void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo, int seq);
void onRequestTvRecordingInfo(in String recordingId, int seq);
void onRequestTvRecordingInfoList(in int type, int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index e362af2..89847a7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -91,7 +91,8 @@
void notifyContentAllowed(in IBinder sessionToken, int userId);
void notifyContentBlocked(in IBinder sessionToken, in String rating, int userId);
void notifySignalStrength(in IBinder sessionToken, int stength, int userId);
- void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, int userId);
+ void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, String requestId,
+ int userId);
void notifyRecordingStopped(in IBinder sessionToken, in String recordingId, int userId);
void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index 8d77141..f17d1b7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -70,7 +70,7 @@
void notifyContentAllowed();
void notifyContentBlocked(in String rating);
void notifySignalStrength(int strength);
- void notifyRecordingStarted(in String recordingId);
+ void notifyRecordingStarted(in String recordingId, in String requestId);
void notifyRecordingStopped(in String recordingId);
void notifyTvMessage(in String type, in Bundle data);
void setSurface(in Surface surface);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index b71f23c..7db8604 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -50,12 +50,12 @@
void onRequestCurrentTvInputId();
void onRequestTimeShiftMode();
void onRequestAvailableSpeeds();
- void onRequestStartRecording(in Uri programUri);
+ void onRequestStartRecording(in String requestId, in Uri programUri);
void onRequestStopRecording(in String recordingId);
- void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
- in Bundle params);
- void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
- long duration, int repeat, in Bundle params);
+ void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+ in Uri programUri, in Bundle params);
+ void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+ long start, long duration, int repeat, in Bundle params);
void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo);
void onRequestTvRecordingInfo(in String recordingId);
void onRequestTvRecordingInfoList(in int type);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index f009cea..ba30e79 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -206,7 +206,9 @@
break;
}
case DO_NOTIFY_RECORDING_STARTED: {
- mSessionImpl.notifyRecordingStarted((String) msg.obj);
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyRecordingStarted((String) args.arg1, (String) args.arg2);
+ args.recycle();
break;
}
case DO_NOTIFY_RECORDING_STOPPED: {
@@ -555,9 +557,9 @@
}
@Override
- public void notifyRecordingStarted(String recordingId) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageO(
- DO_NOTIFY_RECORDING_STARTED, recordingId));
+ public void notifyRecordingStarted(String recordingId, String requestId) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
+ DO_NOTIFY_RECORDING_STARTED, recordingId, recordingId));
}
@Override
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index e6e8c8d..3e31bce3 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -542,14 +542,14 @@
}
@Override
- public void onRequestStartRecording(Uri programUri, int seq) {
+ public void onRequestStartRecording(String requestId, Uri programUri, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postRequestStartRecording(programUri);
+ record.postRequestStartRecording(requestId, programUri);
}
}
@@ -566,21 +566,8 @@
}
@Override
- public void onRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
- Bundle params, int seq) {
- synchronized (mSessionCallbackRecordMap) {
- SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
- if (record == null) {
- Log.e(TAG, "Callback not found for seq " + seq);
- return;
- }
- record.postRequestScheduleRecording(inputId, channelUri, programUri, params);
- }
- }
-
- @Override
- public void onRequestScheduleRecording2(String inputId, Uri channelUri, long startTime,
- long duration, int repeatDays, Bundle params, int seq) {
+ public void onRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ Uri programUri, Bundle params, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
@@ -588,7 +575,22 @@
return;
}
record.postRequestScheduleRecording(
- inputId, channelUri, startTime, duration, repeatDays, params);
+ requestId, inputId, channelUri, programUri, params);
+ }
+ }
+
+ @Override
+ public void onRequestScheduleRecording2(String requestId, String inputId,
+ Uri channelUri, long startTime, long duration, int repeatDays, Bundle params,
+ int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestScheduleRecording(requestId, inputId, channelUri, startTime,
+ duration, repeatDays, params);
}
}
@@ -1267,13 +1269,13 @@
}
}
- void notifyRecordingStarted(String recordingId) {
+ void notifyRecordingStarted(String recordingId, String requestId) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
- mService.notifyRecordingStarted(mToken, recordingId, mUserId);
+ mService.notifyRecordingStarted(mToken, recordingId, requestId, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2129,11 +2131,11 @@
});
}
- void postRequestStartRecording(Uri programUri) {
+ void postRequestStartRecording(String requestId, Uri programUri) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onRequestStartRecording(mSession, programUri);
+ mSessionCallback.onRequestStartRecording(mSession, requestId, programUri);
}
});
}
@@ -2147,24 +2149,24 @@
});
}
- void postRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
- Bundle params) {
+ void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ Uri programUri, Bundle params) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onRequestScheduleRecording(
- mSession, inputId, channelUri, programUri, params);
+ mSession, requestId, inputId, channelUri, programUri, params);
}
});
}
- void postRequestScheduleRecording(String inputId, Uri channelUri, long startTime,
- long duration, int repeatDays, Bundle params) {
+ void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ long startTime, long duration, int repeatDays, Bundle params) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onRequestScheduleRecording(
- mSession, inputId, channelUri, startTime, duration, repeatDays, params);
+ mSessionCallback.onRequestScheduleRecording(mSession, requestId, inputId,
+ channelUri, startTime, duration, repeatDays, params);
}
});
}
@@ -2405,7 +2407,7 @@
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
* @param programUri The Uri of the program to be recorded.
*/
- public void onRequestStartRecording(Session session, Uri programUri) {
+ public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
}
/**
@@ -2420,7 +2422,7 @@
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
* is called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2433,13 +2435,14 @@
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
+ @NonNull Bundle params) {
}
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
* is called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2454,9 +2457,9 @@
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
- @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+ int repeatDays, @NonNull Bundle params) {
}
/**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 4be5523..1ae82f4 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -619,21 +619,28 @@
public void onTvRecordingInfoList(@NonNull List<TvRecordingInfo> recordingInfoList) {}
/**
- * Receives started recording's ID.
+ * This is called when a recording has been started.
+ *
+ * <p>When a scheduled recording is started, this is also called, and the request ID in this
+ * case is {@code null}.
*
* @param recordingId The ID of the recording started. The TV app should provide and
* maintain this ID to identify the recording in the future.
+ * @param requestId The ID of the request when
+ * {@link #requestStartRecording(String, Uri)} is called.
+ * {@code null} if the recording is not triggered by a
+ * {@link #requestStartRecording(String, Uri)} request.
* @see #onRecordingStopped(String)
*/
- public void onRecordingStarted(@NonNull String recordingId) {
+ public void onRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
}
/**
- * Receives stopped recording's ID.
+ * This is called when the recording has been stopped.
*
* @param recordingId The ID of the recording stopped. This ID is created and maintained by
* the TV app when the recording was started.
- * @see #onRecordingStarted(String)
+ * @see #onRecordingStarted(String, String)
*/
public void onRecordingStopped(@NonNull String recordingId) {
}
@@ -643,10 +650,9 @@
* session for the corresponding TV input.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
- * @hide
*/
public void onRecordingConnectionFailed(
@NonNull String recordingId, @NonNull String inputId) {
@@ -656,10 +662,9 @@
* This is called when the connection to the current recording session is lost.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
- * @hide
*/
public void onRecordingDisconnected(@NonNull String recordingId, @NonNull String inputId) {
}
@@ -669,10 +674,9 @@
* ready to start recording.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param channelUri The URI of the tuned channel.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
- * @hide
*/
public void onRecordingTuned(@NonNull String recordingId, @NonNull Uri channelUri) {
}
@@ -682,7 +686,7 @@
* recording session is created until it is released.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param err The error code. Should be one of the following.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -690,7 +694,6 @@
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
* @see android.media.tv.TvRecordingClient.RecordingCallback#onError(int)
- * @hide
*/
public void onRecordingError(
@NonNull String recordingId, @TvInputManager.RecordingError int err) {
@@ -702,9 +705,9 @@
* @param recordingId The ID assigned to this recording by the app. It can be used to send
* recording related requests such as
* {@link #requestStopRecording(String)}.
- * @param requestId The ID of the request when requestScheduleRecording is called.
+ * @param requestId The ID of the request when
+ * {@link #requestScheduleRecording} is called.
* {@code null} if the recording is not triggered by a request.
- * @hide
*/
public void onRecordingScheduled(@NonNull String recordingId, @Nullable String requestId) {
}
@@ -1332,18 +1335,22 @@
* program, whereas null {@code programUri} does not impose such a requirement and the
* recording can span across multiple TV programs.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingStarted(String, String)} for this request is the
+ * same as the ID sent here.
* @param programUri The URI for the TV program to record.
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
@CallSuper
- public void requestStartRecording(@Nullable Uri programUri) {
+ public void requestStartRecording(@NonNull String requestId, @Nullable Uri programUri) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
Log.d(TAG, "requestStartRecording");
}
if (mSessionCallback != null) {
- mSessionCallback.onRequestStartRecording(programUri);
+ mSessionCallback.onRequestStartRecording(requestId, programUri);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestStartRecording", e);
@@ -1358,7 +1365,7 @@
* call {@link android.media.tv.TvRecordingClient#stopRecording()}.
*
* @param recordingId The ID of the recording to stop. This is provided by the TV app in
- * {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @see android.media.tv.TvRecordingClient#stopRecording()
*/
@CallSuper
@@ -1380,6 +1387,10 @@
/**
* Requests scheduling of a recording.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingScheduled(String, String)} for this request is the
+ * same as the ID sent here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param programUri The URI of the TV program to be recorded.
@@ -1388,11 +1399,10 @@
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
@CallSuper
- public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
- @NonNull Uri programUri, @NonNull Bundle params) {
+ public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+ @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
@@ -1400,7 +1410,7 @@
}
if (mSessionCallback != null) {
mSessionCallback.onRequestScheduleRecording(
- inputId, channelUri, programUri, params);
+ requestId, inputId, channelUri, programUri, params);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1411,6 +1421,10 @@
/**
* Requests scheduling of a recording.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingScheduled(String, String)} for this request is the
+ * same as the ID sent here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param startTime The start time of the recording in milliseconds since epoch.
@@ -1421,19 +1435,19 @@
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
@CallSuper
- public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
- long startTime, long duration, int repeatDays, @NonNull Bundle params) {
+ public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+ @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
+ @NonNull Bundle params) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
Log.d(TAG, "requestScheduleRecording");
}
if (mSessionCallback != null) {
- mSessionCallback.onRequestScheduleRecording2(
- inputId, channelUri, startTime, duration, repeatDays, params);
+ mSessionCallback.onRequestScheduleRecording2(requestId, inputId, channelUri,
+ startTime, duration, repeatDays, params);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1445,7 +1459,7 @@
* Sets the recording info for the specified recording
*
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
*/
@CallSuper
@@ -1468,7 +1482,8 @@
/**
* Gets the recording info for the specified recording
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
*/
@CallSuper
public void requestTvRecordingInfo(@NonNull String recordingId) {
@@ -1757,10 +1772,10 @@
}
/**
- * Calls {@link #onRecordingStarted(String)}.
+ * Calls {@link #onRecordingStarted(String, String)}.
*/
- void notifyRecordingStarted(String recordingId) {
- onRecordingStarted(recordingId);
+ void notifyRecordingStarted(String recordingId, String requestId) {
+ onRecordingStarted(recordingId, requestId);
}
/**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index ca47c2c..0a8de12 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -667,19 +667,22 @@
}
/**
- * Alerts the TV interactive app that a recording has been started.
+ * Alerts the related TV interactive app service that a recording has been started.
*
* @param recordingId The ID of the recording started. This ID is created and maintained by the
* TV app and is used to identify the recording in the future.
+ *
+ * @param requestId The ID of the request when
+ * {@link TvInteractiveAppService.Session#requestStartRecording(String, Uri)}
+ * is called. {@code null} if the recording is not triggered by a request.
* @see TvInteractiveAppView#notifyRecordingStopped(String)
*/
- public void notifyRecordingStarted(@NonNull String recordingId) {
- // TODO: add request ID to identify and map the corresponding request.
+ public void notifyRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
if (DEBUG) {
Log.d(TAG, "notifyRecordingStarted");
}
if (mSession != null) {
- mSession.notifyRecordingStarted(recordingId);
+ mSession.notifyRecordingStarted(recordingId, recordingId);
}
}
@@ -688,7 +691,7 @@
*
* @param recordingId The ID of the recording stopped. This ID is created and maintained
* by the TV app when a recording is started.
- * @see TvInteractiveAppView#notifyRecordingStarted(String)
+ * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
*/
public void notifyRecordingStopped(@NonNull String recordingId) {
if (DEBUG) {
@@ -824,7 +827,7 @@
* while establishing a connection to the recording session for the corresponding TV input.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
* @hide
@@ -845,7 +848,7 @@
* the current recording session is lost.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
* @hide
@@ -866,7 +869,7 @@
* has been tuned to the given channel and is ready to start recording.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param channelUri The URI of the tuned channel.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
* @hide
@@ -888,7 +891,7 @@
* it is released.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param err The error code. Should be one of the following.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -916,9 +919,9 @@
* @param recordingId The ID assigned to this recording by the app. It can be used to send
* recording related requests such as
* {@link TvInteractiveAppService.Session#requestStopRecording(String)}.
- * @param requestId The ID of the request when requestScheduleRecording is called.
+ * @param requestId The ID of the request when
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording} is called.
* {@code null} if the recording is not triggered by a request.
- * @hide
*/
public void notifyRecordingScheduled(
@NonNull String recordingId, @Nullable String requestId) {
@@ -1215,12 +1218,15 @@
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingStarted(String, String)}
+ * for this request should be the same as the ID received here.
* @param programUri The URI of the program to record
*
*/
- public void onRequestStartRecording(
- @NonNull String iAppServiceId,
- @Nullable Uri programUri) {
+ public void onRequestStartRecording(@NonNull String iAppServiceId,
+ @NonNull String requestId, @Nullable Uri programUri) {
}
/**
@@ -1229,8 +1235,8 @@
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to stop. This is provided by the TV app in
- * {@link #notifyRecordingStarted(String)}
- * @see #notifyRecordingStarted(String)
+ * {@link #notifyRecordingStarted(String, String)}
+ * @see #notifyRecordingStarted(String, String)
* @see #notifyRecordingStopped(String)
*/
public void onRequestStopRecording(
@@ -1240,10 +1246,14 @@
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingScheduled(String, String)} for this request
+ * should be the same as the ID received here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param programUri The URI of the TV program to be recorded.
@@ -1252,19 +1262,22 @@
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
public void onRequestScheduleRecording(@NonNull String iAppServiceId,
- @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
- @NonNull Bundle params) {
+ @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+ @NonNull Uri programUri, @NonNull Bundle params) {
}
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingScheduled(String, String)} for this request
+ * should be the same as the ID received here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param startTime The start time of the recording in milliseconds since epoch.
@@ -1275,11 +1288,10 @@
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
public void onRequestScheduleRecording(@NonNull String iAppServiceId,
- @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
- int repeatDays, @NonNull Bundle params) {
+ @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+ long startTime, long duration, int repeatDays, @NonNull Bundle params) {
}
/**
@@ -1304,7 +1316,7 @@
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
*/
public void onSetTvRecordingInfo(
@@ -1320,7 +1332,8 @@
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to get the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
*/
public void onRequestTvRecordingInfo(
@NonNull String iAppServiceId,
@@ -1724,7 +1737,7 @@
}
@Override
- public void onRequestStartRecording(Session session, Uri programUri) {
+ public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
if (DEBUG) {
Log.d(TAG, "onRequestStartRecording");
}
@@ -1733,7 +1746,7 @@
return;
}
if (mCallback != null) {
- mCallback.onRequestStartRecording(mIAppServiceId, programUri);
+ mCallback.onRequestStartRecording(mIAppServiceId, requestId, programUri);
}
}
@@ -1767,8 +1780,9 @@
}
@Override
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, Uri progarmUri, @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, Uri programUri,
+ @NonNull Bundle params) {
if (DEBUG) {
Log.d(TAG, "onRequestScheduleRecording");
}
@@ -1777,8 +1791,24 @@
return;
}
if (mCallback != null) {
- mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri,
- progarmUri, params);
+ mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+ programUri, params);
+ }
+ }
+
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+ int repeatDays, @NonNull Bundle params) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestScheduleRecording");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestScheduleRecording - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+ startTime, duration, repeatDays, params);
}
}
@@ -1812,22 +1842,6 @@
}
}
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
- @NonNull Bundle params) {
- if (DEBUG) {
- Log.d(TAG, "onRequestScheduleRecording");
- }
- if (this != mSessionCallback) {
- Log.w(TAG, "onRequestScheduleRecording - session not created");
- return;
- }
- if (mCallback != null) {
- mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri, startTime,
- duration, repeatDays, params);
- }
- }
-
@Override
public void onRequestSigning(
Session session, String id, String algorithm, String alias, byte[] data) {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d08b81..5a56945 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -805,6 +805,7 @@
acquireTRMSLock("close()");
try {
releaseAll();
+ mTunerResourceManager.unregisterClientProfile(mClientId);
TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner");
} finally {
releaseTRMSLock();
@@ -968,7 +969,6 @@
releaseDescramblers();
releaseFilters();
releaseDemux();
- mTunerResourceManager.unregisterClientProfile(mClientId);
}
/**
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
new file mode 100644
index 0000000..97d201d
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_neutral1_200">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
new file mode 100644
index 0000000..af4fe4d
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_accent1_200">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
index 5f8d566..9065520 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
@@ -16,23 +16,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:width="24dp"
- android:viewportHeight="160"
- android:viewportWidth="160" >
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M69.48,83.33A26.97,24.46 0,0 1,42.92 107.8,26.97 24.46,0 0,1 15.56,84.07 26.97,24.46 0,0 1,41.29 58.9,26.97 24.46,0 0,1 69.43,81.86"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="m143.73,83.58a26.97,24.46 0,0 1,-26.56 24.46,26.97 24.46,0 0,1 -27.36,-23.72 26.97,24.46 0,0 1,25.73 -25.18,26.97 24.46,0 0,1 28.14,22.96"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="m69.42,82.98c20.37,-0.25 20.37,-0.25 20.37,-0.25"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M15.37,83.78 L1.9,56.83"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M143.67,82.75C154.48,57.9 154.48,58.04 154.48,58.04"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
index 7295e78..d890afd 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
@@ -22,7 +22,6 @@
android:viewportHeight="24"
android:tint="@android:color/system_accent1_600">
<path
- android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
- android:fillColor="#3C4043"
- android:fillType="evenOdd"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index bf69ef4..f64a432 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -26,7 +26,6 @@
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
-import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
@@ -35,6 +34,7 @@
import com.android.credentialmanager.common.Constants
import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
+import com.android.credentialmanager.common.StartBalIntentSenderForResultContract
import com.android.credentialmanager.createflow.CreateCredentialScreen
import com.android.credentialmanager.getflow.GetCredentialScreen
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
@@ -84,7 +84,7 @@
CredentialSelectorViewModel(credManRepo, userConfigRepo)
}
val launcher = rememberLauncherForActivityResult(
- ActivityResultContracts.StartIntentSenderForResult()
+ StartBalIntentSenderForResultContract()
) {
viewModel.onProviderActivityResult(ProviderActivityResult(it.resultCode, it.data))
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
new file mode 100644
index 0000000..9952815
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.credentialmanager.common
+
+import android.app.ActivityOptions
+import android.content.Context
+import android.content.Intent
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.IntentSenderRequest
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts
+
+/**
+ * A custom StartIntentSenderForResult contract implementation that attaches an [ActivityOptions]
+ * that opts in for background activity launch.
+ */
+class StartBalIntentSenderForResultContract :
+ ActivityResultContract<IntentSenderRequest, ActivityResult>() {
+ override fun createIntent(context: Context, input: IntentSenderRequest): Intent {
+ val activityOptionBundle =
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ ).toBundle()
+ return Intent(
+ ActivityResultContracts.StartIntentSenderForResult.ACTION_INTENT_SENDER_REQUEST
+ ).putExtra(
+ ActivityResultContracts.StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE,
+ activityOptionBundle
+ ).putExtra(
+ ActivityResultContracts.StartIntentSenderForResult.EXTRA_INTENT_SENDER_REQUEST,
+ input
+ )
+ }
+
+ override fun parseResult(
+ resultCode: Int,
+ intent: Intent?
+ ): ActivityResult = ActivityResult(resultCode, intent)
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
index 4b4cfb7..0cd9fe3 100644
--- a/packages/SettingsLib/ActivityEmbedding/Android.bp
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -30,6 +30,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index af7b8b4..0ba47a8 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -23,6 +23,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 50f8e54..6330848f 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -28,6 +28,6 @@
"com.android.adservices",
"com.android.cellbroadcast",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
index bcedf50..8b976bb 100644
--- a/packages/SettingsLib/FooterPreference/Android.bp
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -23,6 +23,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 3ec4366a..13fcf8c 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -22,6 +22,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 372a276..825e6ac 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -25,6 +25,6 @@
"//apex_available:platform",
"com.android.adservices",
"com.android.cellbroadcast",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 939977f..09691f1 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -23,7 +23,7 @@
"com.android.cellbroadcast",
"com.android.permission",
"com.android.adservices",
- "com.android.healthconnect",
+ "com.android.healthfitness",
"com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index be77845..7f9014c 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -23,6 +23,6 @@
"com.android.adservices",
"com.android.cellbroadcast",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 9117524a..42af999 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -19,7 +19,7 @@
BUILD_TOOLS_VERSION = "30.0.3"
MIN_SDK = 21
TARGET_SDK = 33
- jetpack_compose_version = '1.4.0-alpha05'
+ jetpack_compose_version = '1.4.0-beta01'
jetpack_compose_compiler_version = '1.4.0'
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
index 08e6452..5f251b1 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
@@ -64,7 +64,7 @@
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "ItemList_$opParam",
+ label = "ItemList_$opParam",
).setUiLayoutFn {
Preference(
object : PreferenceModel {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
index 8179356..98b27b7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
@@ -99,7 +99,7 @@
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "ItemOp_$opParam",
+ label = "ItemOp_$opParam",
).setUiLayoutFn {
// Item name is a runtime parameter, which needs to be read inside UiLayoutFn
val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, it) ?: "NULL"
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index eca47b6..f01ff38 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -87,7 +87,7 @@
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "${name}_$stringParam",
+ label = "${name}_$stringParam",
)
.setSearchDataFn { ArgumentPageModel.genInjectSearchData() }
.setUiLayoutFn {
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
index 6bf20be..f513830 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
index fa01348..73f2407 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
index 7e57958..6e860d3 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 6f1b41c..640aa01 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -69,18 +69,16 @@
}
dependencies {
- String jetpack_lifecycle_version = "2.6.0-alpha03"
-
- api "androidx.appcompat:appcompat:1.7.0-alpha01"
+ api "androidx.appcompat:appcompat:1.7.0-alpha02"
api "androidx.slice:slice-builders:1.1.0-alpha02"
api "androidx.slice:slice-core:1.1.0-alpha02"
api "androidx.slice:slice-view:1.1.0-alpha02"
- api "androidx.compose.material3:material3:1.1.0-alpha05"
+ api "androidx.compose.material3:material3:1.1.0-alpha06"
api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
- api "androidx.compose.runtime:runtime-livedata:1.4.0-alpha04"
+ api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
- api "androidx.lifecycle:lifecycle-livedata-ktx:$jetpack_lifecycle_version"
- api "androidx.lifecycle:lifecycle-runtime-compose:$jetpack_lifecycle_version"
+ api "androidx.lifecycle:lifecycle-livedata-ktx"
+ api "androidx.lifecycle:lifecycle-runtime-compose"
api "androidx.navigation:navigation-compose:2.6.0-alpha04"
api "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha"
api "com.google.android.material:material:1.7.0-alpha03"
@@ -108,7 +106,6 @@
// Excludes files forked from Accompanist.
"com/android/settingslib/spa/framework/compose/DrawablePainter*",
- "com/android/settingslib/spa/framework/compose/Pager*",
// Excludes inline functions, which is not covered in Jacoco reports.
"com/android/settingslib/spa/framework/util/Collections*",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
index d95ed05..444a3f0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
@@ -50,22 +50,22 @@
}
fun SettingsEntry.debugBrief(): String {
- return "${owner.displayName}:$displayName"
+ return "${owner.displayName}:$label"
}
fun SettingsEntry.debugContent(entryRepository: SettingsEntryRepository): String {
val searchData = getSearchData()
val statusData = getStatusData()
- val entryPathWithName = entryRepository.getEntryPathWithDisplayName(id)
+ val entryPathWithLabel = entryRepository.getEntryPathWithLabel(id)
val entryPathWithTitle = entryRepository.getEntryPathWithTitle(id,
- searchData?.title ?: displayName)
+ searchData?.title ?: label)
val content = listOf(
"------ STATIC ------",
"id = $id",
"owner = ${owner.debugBrief()} ${owner.debugArguments()}",
"linkFrom = ${fromPage?.debugBrief()} ${fromPage?.debugArguments()}",
"linkTo = ${toPage?.debugBrief()} ${toPage?.debugArguments()}",
- "hierarchy_path = $entryPathWithName",
+ "hierarchy_path = $entryPathWithLabel",
"------ ATTRIBUTION ------",
"allowSearch = $isAllowSearch",
"isSearchDynamic = $isSearchDataDynamic",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
index 494e3cc..1fcc888 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
@@ -173,12 +173,12 @@
val intent = entry.createIntent(SESSION_SEARCH) ?: Intent()
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
- .add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
.add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
.add(
ColumnEnum.ENTRY_HIERARCHY_PATH.id,
- entryRepository.getEntryPathWithDisplayName(entry.id)
+ entryRepository.getEntryPathWithLabel(entry.id)
)
}
return cursor
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
index fc6160e..9b46ec2 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
@@ -33,7 +33,7 @@
// Columns related to entry
ENTRY_ID("entryId"),
- ENTRY_NAME("entryName"),
+ ENTRY_LABEL("entryLabel"),
ENTRY_ROUTE("entryRoute"),
ENTRY_INTENT_URI("entryIntent"),
ENTRY_HIERARCHY_PATH("entryPath"),
@@ -76,7 +76,7 @@
"entry_info", 200,
listOf(
ColumnEnum.ENTRY_ID,
- ColumnEnum.ENTRY_NAME,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_ROUTE,
ColumnEnum.ENTRY_INTENT_URI,
ColumnEnum.ENTRY_HIERARCHY_PATH,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index b92729d..90581b9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -51,11 +51,13 @@
// The unique id of this entry, which is computed by name + owner + fromPage + toPage.
val id: String,
- // The name of the page, which is used to compute the unique id, and need to be stable.
+ // The name of the entry, which is used to compute the unique id, and need to be stable.
private val name: String,
- // The display name of the page, for better readability.
- val displayName: String,
+ // The label of the entry, for better readability.
+ // For migration mapping, this should match the android:key field in the old architecture
+ // if applicable.
+ val label: String,
// The owner page of this entry.
val owner: SettingsPage,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
index 67f9ea5..97d8de3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -21,14 +21,14 @@
import androidx.compose.runtime.remember
import com.android.settingslib.spa.framework.util.genEntryId
-private const val INJECT_ENTRY_NAME = "INJECT"
-private const val ROOT_ENTRY_NAME = "ROOT"
+private const val INJECT_ENTRY_LABEL = "INJECT"
+private const val ROOT_ENTRY_LABEL = "ROOT"
/**
* The helper to build a Settings Entry instance.
*/
class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
- private var displayName = name
+ private var label = name
private var fromPage: SettingsPage? = null
private var toPage: SettingsPage? = null
@@ -51,7 +51,7 @@
id = genEntryId(name, owner, fromPage, toPage),
name = name,
owner = owner,
- displayName = displayName,
+ label = label,
// linking data
fromPage = fromPage,
@@ -72,8 +72,8 @@
)
}
- fun setDisplayName(displayName: String): SettingsEntryBuilder {
- this.displayName = displayName
+ fun setLabel(label: String): SettingsEntryBuilder {
+ this.label = label
return this
}
@@ -147,19 +147,19 @@
return create(entryName, owner).setLink(toPage = owner)
}
- fun create(owner: SettingsPage, entryName: String, displayName: String? = null):
+ fun create(owner: SettingsPage, entryName: String, label: String? = null):
SettingsEntryBuilder {
- return SettingsEntryBuilder(entryName, owner).setDisplayName(displayName ?: entryName)
+ return SettingsEntryBuilder(entryName, owner).setLabel(label ?: entryName)
}
- fun createInject(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${INJECT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(INJECT_ENTRY_NAME, owner).setDisplayName(name)
+ fun createInject(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+ val label = label ?: "${INJECT_ENTRY_LABEL}_${owner.displayName}"
+ return createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
}
- fun createRoot(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${ROOT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(ROOT_ENTRY_NAME, owner).setDisplayName(name)
+ fun createRoot(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+ val label = label ?: "${ROOT_ENTRY_LABEL}_${owner.displayName}"
+ return createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index 429f97b..8811b94 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -111,9 +111,9 @@
return entryPath
}
- fun getEntryPathWithDisplayName(entryId: String): List<String> {
+ fun getEntryPathWithLabel(entryId: String): List<String> {
val entryPath = getEntryPath(entryId)
- return entryPath.map { it.displayName }
+ return entryPath.map { it.label }
}
fun getEntryPathWithTitle(entryId: String, defaultTitle: String): List<String> {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
deleted file mode 100644
index 392089a..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * 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.settingslib.spa.framework.compose
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
-import kotlinx.coroutines.flow.filter
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/Pager.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * A horizontally scrolling layout that allows users to flip between items to the left and right.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the end to the start and [PagerState.currentPage] == 0 will mean
- * the first item is located at the end.
- * @param itemSpacing horizontal spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun HorizontalPager(
- count: Int,
- modifier: Modifier = Modifier,
- state: PagerState = rememberPagerState(),
- reverseLayout: Boolean = false,
- itemSpacing: Dp = 0.dp,
- contentPadding: PaddingValues = PaddingValues(0.dp),
- verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
- key: ((page: Int) -> Any)? = null,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- Pager(
- count = count,
- state = state,
- modifier = modifier,
- isVertical = false,
- reverseLayout = reverseLayout,
- itemSpacing = itemSpacing,
- verticalAlignment = verticalAlignment,
- key = key,
- contentPadding = contentPadding,
- content = content
- )
-}
-
-/**
- * A vertically scrolling layout that allows users to flip between items to the top and bottom.
- *
- * @sample com.google.accompanist.sample.pager.VerticalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean
- * the first item is located at the bottom.
- * @param itemSpacing vertical spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun VerticalPager(
- count: Int,
- modifier: Modifier = Modifier,
- state: PagerState = rememberPagerState(),
- reverseLayout: Boolean = false,
- itemSpacing: Dp = 0.dp,
- contentPadding: PaddingValues = PaddingValues(0.dp),
- horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
- key: ((page: Int) -> Any)? = null,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- Pager(
- count = count,
- state = state,
- modifier = modifier,
- isVertical = true,
- reverseLayout = reverseLayout,
- itemSpacing = itemSpacing,
- horizontalAlignment = horizontalAlignment,
- key = key,
- contentPadding = contentPadding,
- content = content
- )
-}
-
-@Composable
-internal fun Pager(
- count: Int,
- modifier: Modifier,
- state: PagerState,
- reverseLayout: Boolean,
- itemSpacing: Dp,
- isVertical: Boolean,
- key: ((page: Int) -> Any)?,
- contentPadding: PaddingValues,
- verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
- horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- require(count >= 0) { "pageCount must be >= 0" }
-
- LaunchedEffect(count) {
- state.currentPage = minOf(count - 1, state.currentPage).coerceAtLeast(0)
- }
-
- // Once a fling (scroll) has finished, notify the state
- LaunchedEffect(state) {
- // When a 'scroll' has finished, notify the state
- snapshotFlow { state.isScrollInProgress }
- .filter { !it }
- // initially isScrollInProgress is false as well and we want to start receiving
- // the events only after the real scroll happens.
- .drop(1)
- .collect { state.onScrollFinished() }
- }
- LaunchedEffect(state) {
- snapshotFlow { state.mostVisiblePageLayoutInfo?.index }
- .distinctUntilChanged()
- .collect { state.updateCurrentPageBasedOnLazyListState() }
- }
- val density = LocalDensity.current
- LaunchedEffect(density, state, itemSpacing) {
- with(density) { state.itemSpacing = itemSpacing.roundToPx() }
- }
-
- val pagerScope = remember(state) { PagerScopeImpl(state) }
-
- // We only consume nested flings in the main-axis, allowing cross-axis flings to propagate
- // as normal
- val consumeFlingNestedScrollConnection = remember(isVertical) {
- ConsumeFlingNestedScrollConnection(
- consumeHorizontal = !isVertical,
- consumeVertical = isVertical,
- pagerState = state,
- )
- }
-
- if (isVertical) {
- LazyColumn(
- state = state.lazyListState,
- verticalArrangement = Arrangement.spacedBy(itemSpacing, verticalAlignment),
- horizontalAlignment = horizontalAlignment,
- reverseLayout = reverseLayout,
- contentPadding = contentPadding,
- userScrollEnabled = false,
- modifier = modifier,
- ) {
- items(
- count = count,
- key = key,
- ) { page ->
- Box(
- Modifier
- // We don't any nested flings to continue in the pager, so we add a
- // connection which consumes them.
- // See: https://github.com/google/accompanist/issues/347
- .nestedScroll(connection = consumeFlingNestedScrollConnection)
- // Constraint the content height to be <= than the height of the pager.
- .fillParentMaxHeight()
- .wrapContentSize()
- ) {
- pagerScope.content(page)
- }
- }
- }
- } else {
- LazyRow(
- state = state.lazyListState,
- verticalAlignment = verticalAlignment,
- horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
- reverseLayout = reverseLayout,
- contentPadding = contentPadding,
- userScrollEnabled = false,
- modifier = modifier,
- ) {
- items(
- count = count,
- key = key,
- ) { page ->
- Box(
- Modifier
- // We don't any nested flings to continue in the pager, so we add a
- // connection which consumes them.
- // See: https://github.com/google/accompanist/issues/347
- .nestedScroll(connection = consumeFlingNestedScrollConnection)
- // Constraint the content width to be <= than the width of the pager.
- .fillParentMaxWidth()
- .wrapContentSize()
- ) {
- pagerScope.content(page)
- }
- }
- }
- }
-}
-
-private class ConsumeFlingNestedScrollConnection(
- private val consumeHorizontal: Boolean,
- private val consumeVertical: Boolean,
- private val pagerState: PagerState,
-) : NestedScrollConnection {
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource
- ): Offset = when (source) {
- // We can consume all resting fling scrolls so that they don't propagate up to the
- // Pager
- NestedScrollSource.Fling -> available.consume(consumeHorizontal, consumeVertical)
- else -> Offset.Zero
- }
-
- override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
- return if (pagerState.currentPageOffset != 0f) {
- // The Pager is already scrolling. This means that a nested scroll child was
- // scrolled to end, and the Pager can use this fling
- Velocity.Zero
- } else {
- // A nested scroll child is still scrolling. We can consume all post fling
- // velocity on the main-axis so that it doesn't propagate up to the Pager
- available.consume(consumeHorizontal, consumeVertical)
- }
- }
-}
-
-private fun Offset.consume(
- consumeHorizontal: Boolean,
- consumeVertical: Boolean,
-): Offset = Offset(
- x = if (consumeHorizontal) this.x else 0f,
- y = if (consumeVertical) this.y else 0f,
-)
-
-private fun Velocity.consume(
- consumeHorizontal: Boolean,
- consumeVertical: Boolean,
-): Velocity = Velocity(
- x = if (consumeHorizontal) this.x else 0f,
- y = if (consumeVertical) this.y else 0f,
-)
-
-/**
- * Scope for [HorizontalPager] content.
- */
-@Stable
-interface PagerScope {
- /**
- * Returns the current selected page
- */
- val currentPage: Int
-
- /**
- * The current offset from the start of [currentPage], as a ratio of the page width.
- */
- val currentPageOffset: Float
-}
-
-private class PagerScopeImpl(
- private val state: PagerState,
-) : PagerScope {
- override val currentPage: Int get() = state.currentPage
- override val currentPageOffset: Float get() = state.currentPageOffset
-}
-
-/**
- * Calculate the offset for the given [page] from the current scroll position. This is useful
- * when using the scroll position to apply effects or animations to items.
- *
- * The returned offset can positive or negative, depending on whether which direction the [page] is
- * compared to the current scroll position.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerWithOffsetTransition
- */
-fun PagerScope.calculateCurrentOffsetForPage(page: Int): Float {
- return (currentPage - page) + currentPageOffset
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
deleted file mode 100644
index 480335d..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * 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.settingslib.spa.framework.compose
-
-import androidx.annotation.FloatRange
-import androidx.annotation.IntRange
-import androidx.compose.foundation.MutatePriority
-import androidx.compose.foundation.gestures.ScrollScope
-import androidx.compose.foundation.gestures.ScrollableState
-import androidx.compose.foundation.interaction.InteractionSource
-import androidx.compose.foundation.lazy.LazyListItemInfo
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.Saver
-import androidx.compose.runtime.saveable.listSaver
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import kotlin.math.abs
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/PagerState.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * Creates a [PagerState] that is remembered across compositions.
- *
- * Changes to the provided values for [initialPage] will **not** result in the state being
- * recreated or changed in any way if it has already
- * been created.
- *
- * @param initialPage the initial value for [PagerState.currentPage]
- */
-@Composable
-fun rememberPagerState(
- @IntRange(from = 0) initialPage: Int = 0,
-): PagerState = rememberSaveable(saver = PagerState.Saver) {
- PagerState(
- currentPage = initialPage,
- )
-}
-
-/**
- * A state object that can be hoisted to control and observe scrolling for [HorizontalPager].
- *
- * In most cases, this will be created via [rememberPagerState].
- *
- * @param currentPage the initial value for [PagerState.currentPage]
- */
-@Stable
-class PagerState(
- @IntRange(from = 0) currentPage: Int = 0,
-) : ScrollableState {
- // Should this be public?
- internal val lazyListState = LazyListState(firstVisibleItemIndex = currentPage)
-
- private var _currentPage by mutableStateOf(currentPage)
-
- // finds the page which has larger visible area within the viewport not including paddings
- internal val mostVisiblePageLayoutInfo: LazyListItemInfo?
- get() {
- val layoutInfo = lazyListState.layoutInfo
- return layoutInfo.visibleItemsInfo.maxByOrNull {
- val start = maxOf(it.offset, 0)
- val end = minOf(
- it.offset + it.size,
- layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding
- )
- end - start
- }
- }
-
- internal var itemSpacing by mutableStateOf(0)
-
- private val currentPageLayoutInfo: LazyListItemInfo?
- get() = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull {
- it.index == currentPage
- }
-
- /**
- * [InteractionSource] that will be used to dispatch drag events when this
- * list is being dragged. If you want to know whether the fling (or animated scroll) is in
- * progress, use [isScrollInProgress].
- */
- val interactionSource: InteractionSource
- get() = lazyListState.interactionSource
-
- /**
- * The number of pages to display.
- */
- @get:IntRange(from = 0)
- val pageCount: Int by derivedStateOf {
- lazyListState.layoutInfo.totalItemsCount
- }
-
- /**
- * The index of the currently selected page. This may not be the page which is
- * currently displayed on screen.
- *
- * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
- */
- @get:IntRange(from = 0)
- var currentPage: Int
- get() = _currentPage
- internal set(value) {
- if (value != _currentPage) {
- _currentPage = value
- }
- }
-
- /**
- * The current offset from the start of [currentPage], as a ratio of the page width.
- *
- * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
- */
- val currentPageOffset: Float by derivedStateOf {
- currentPageLayoutInfo?.let {
- (-it.offset / (it.size + itemSpacing).toFloat()).coerceIn(-0.5f, 0.5f)
- } ?: 0f
- }
-
- /**
- * The target page for any on-going animations.
- */
- private var animationTargetPage: Int? by mutableStateOf(null)
-
- /**
- * Animate (smooth scroll) to the given page to the middle of the viewport.
- *
- * Cancels the currently running scroll, if any, and suspends until the cancellation is
- * complete.
- *
- * @param page the page to animate to. Must be >= 0.
- * @param pageOffset the percentage of the page size to offset, from the start of [page].
- * Must be in the range -1f..1f.
- */
- suspend fun animateScrollToPage(
- @IntRange(from = 0) page: Int,
- @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
- ) {
- requireCurrentPage(page, "page")
- requireCurrentPageOffset(pageOffset, "pageOffset")
- try {
- animationTargetPage = page
-
- // pre-jump to nearby item for long jumps as an optimization
- // the same trick is done in ViewPager2
- val oldPage = lazyListState.firstVisibleItemIndex
- if (abs(page - oldPage) > 3) {
- lazyListState.scrollToItem(if (page > oldPage) page - 3 else page + 3)
- }
-
- if (pageOffset.absoluteValue <= 0.005f) {
- // If the offset is (close to) zero, just call animateScrollToItem and we're done
- lazyListState.animateScrollToItem(index = page)
- } else {
- // Else we need to figure out what the offset is in pixels...
- lazyListState.scroll { } // this will await for the first layout.
- val layoutInfo = lazyListState.layoutInfo
- var target = layoutInfo.visibleItemsInfo
- .firstOrNull { it.index == page }
-
- if (target != null) {
- // If we have access to the target page layout, we can calculate the pixel
- // offset from the size
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
- )
- } else if (layoutInfo.visibleItemsInfo.isNotEmpty()) {
- // If we don't, we use the current page size as a guide
- val currentSize = layoutInfo.visibleItemsInfo.first().size + itemSpacing
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = (currentSize * pageOffset).roundToInt()
- )
-
- // The target should be visible now
- target = layoutInfo.visibleItemsInfo.firstOrNull { it.index == page }
-
- if (target != null && target.size + itemSpacing != currentSize) {
- // If the size we used for calculating the offset differs from the actual
- // target page size, we need to scroll again. This doesn't look great,
- // but there's not much else we can do.
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
- )
- }
- }
- }
- } finally {
- // We need to manually call this, as the `animateScrollToItem` call above will happen
- // in 1 frame, which is usually too fast for the LaunchedEffect in Pager to detect
- // the change. This is especially true when running unit tests.
- onScrollFinished()
- }
- }
-
- /**
- * Instantly brings the item at [page] to the middle of the viewport.
- *
- * Cancels the currently running scroll, if any, and suspends until the cancellation is
- * complete.
- *
- * @param page the page to snap to. Must be >= 0.
- * @param pageOffset the percentage of the page size to offset, from the start of [page].
- * Must be in the range -1f..1f.
- */
- suspend fun scrollToPage(
- @IntRange(from = 0) page: Int,
- @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
- ) {
- requireCurrentPage(page, "page")
- requireCurrentPageOffset(pageOffset, "pageOffset")
- try {
- animationTargetPage = page
-
- // First scroll to the given page. It will now be laid out at offset 0
- lazyListState.scrollToItem(index = page)
- updateCurrentPageBasedOnLazyListState()
-
- // If we have a start spacing, we need to offset (scroll) by that too
- if (pageOffset.absoluteValue > 0.0001f) {
- currentPageLayoutInfo?.let {
- scroll {
- scrollBy((it.size + itemSpacing) * pageOffset)
- }
- }
- }
- } finally {
- // We need to manually call this, as the `scroll` call above will happen in 1 frame,
- // which is usually too fast for the LaunchedEffect in Pager to detect the change.
- // This is especially true when running unit tests.
- onScrollFinished()
- }
- }
-
- internal fun updateCurrentPageBasedOnLazyListState() {
- // Then update the current page to our layout page
- mostVisiblePageLayoutInfo?.let {
- currentPage = it.index
- }
- }
-
- internal fun onScrollFinished() {
- // Clear the animation target page
- animationTargetPage = null
- }
-
- override suspend fun scroll(
- scrollPriority: MutatePriority,
- block: suspend ScrollScope.() -> Unit
- ) = lazyListState.scroll(scrollPriority, block)
-
- override fun dispatchRawDelta(delta: Float): Float {
- return lazyListState.dispatchRawDelta(delta)
- }
-
- override val isScrollInProgress: Boolean
- get() = lazyListState.isScrollInProgress
-
- override fun toString(): String = "PagerState(" +
- "pageCount=$pageCount, " +
- "currentPage=$currentPage, " +
- "currentPageOffset=$currentPageOffset" +
- ")"
-
- private fun requireCurrentPage(value: Int, name: String) {
- require(value >= 0) { "$name[$value] must be >= 0" }
- }
-
- private fun requireCurrentPageOffset(value: Float, name: String) {
- require(value in -1f..1f) { "$name must be >= -1 and <= 1" }
- }
-
- companion object {
- /**
- * The default [Saver] implementation for [PagerState].
- */
- val Saver: Saver<PagerState, *> = listSaver(
- save = {
- listOf<Any>(
- it.currentPage,
- )
- },
- restore = {
- PagerState(
- currentPage = it[0] as Int,
- )
- }
- )
- }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
index e6fa74e..26372b6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
@@ -17,6 +17,9 @@
package com.android.settingslib.spa.framework.theme
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.ripple.LocalRippleTheme
+import androidx.compose.material.ripple.RippleAlpha
+import androidx.compose.material.ripple.RippleTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -33,8 +36,11 @@
background = settingsColorScheme.background,
)
- CompositionLocalProvider(LocalColorScheme provides settingsColorScheme(isDarkTheme)) {
- MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+ MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+ CompositionLocalProvider(
+ LocalColorScheme provides settingsColorScheme(isDarkTheme),
+ LocalRippleTheme provides SettingsRippleTheme,
+ ) {
content()
}
}
@@ -46,3 +52,19 @@
@ReadOnlyComposable
get() = LocalColorScheme.current
}
+
+private object SettingsRippleTheme : RippleTheme {
+ @Composable
+ override fun defaultColor() = MaterialTheme.colorScheme.onSurface
+
+ @Composable
+ override fun rippleAlpha() = RippleAlpha
+}
+
+/** Alpha levels for all content. */
+private val RippleAlpha = RippleAlpha(
+ pressedAlpha = 0.48f,
+ focusedAlpha = 0.48f,
+ draggedAlpha = 0.32f,
+ hoveredAlpha = 0.16f,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
index 83dcd13..780933d3c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
@@ -43,6 +43,7 @@
/** Enum to define all column names in provider. */
enum class ColumnEnum(val id: String) {
ENTRY_ID("entryId"),
+ ENTRY_LABEL("entryLabel"),
SEARCH_TITLE("searchTitle"),
SEARCH_KEYWORD("searchKw"),
SEARCH_PATH("searchPath"),
@@ -50,7 +51,6 @@
INTENT_TARGET_CLASS("intentTargetClass"),
INTENT_EXTRAS("intentExtras"),
SLICE_URI("sliceUri"),
- LEGACY_KEY("legacyKey"),
ENTRY_DISABLED("entryDisabled"),
}
@@ -64,6 +64,7 @@
SEARCH_STATIC_DATA,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -71,13 +72,13 @@
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY
)
),
SEARCH_DYNAMIC_DATA_QUERY(
SEARCH_DYNAMIC_DATA,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -85,13 +86,13 @@
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY
)
),
SEARCH_IMMUTABLE_STATUS_DATA_QUERY(
SEARCH_IMMUTABLE_STATUS,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -99,6 +100,7 @@
SEARCH_MUTABLE_STATUS,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -106,6 +108,7 @@
SEARCH_STATIC_ROW,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -113,7 +116,6 @@
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -121,6 +123,7 @@
SEARCH_DYNAMIC_ROW,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -128,7 +131,6 @@
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY,
ColumnEnum.ENTRY_DISABLED,
)
),
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index 057f13f..eacb28c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -42,7 +42,7 @@
* One can query the provider result by:
* $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
* For gallery, AuthorityPath = com.android.spa.gallery.search.provider
- * For Settings, AuthorityPath = com.android.settings.spa.search.provider"
+ * For Settings, AuthorityPath = com.android.settings.spa.search.provider
* Some examples:
* $ adb shell content query --uri content://<AuthorityPath>/search_static_data
* $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
@@ -205,6 +205,7 @@
val searchData = entry.getSearchData() ?: return
val intent = entry.createIntent(SESSION_SEARCH)
val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
.add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
.add(
@@ -221,7 +222,6 @@
ColumnEnum.SLICE_URI.id, Uri.Builder()
.fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
)
- // TODO: support legacy key
}
private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
@@ -229,6 +229,7 @@
val statusData = entry.getStatusData() ?: return
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
}
@@ -239,6 +240,7 @@
val searchData = entry.getSearchData() ?: return
val intent = entry.createIntent(SESSION_SEARCH)
val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
.add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
.add(
@@ -255,8 +257,6 @@
ColumnEnum.SLICE_URI.id, Uri.Builder()
.fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
)
- // TODO: support legacy key
-
// Fetch status data. We can add runtime arguments later if necessary
val statusData = entry.getStatusData() ?: return
row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
index b8c59ad..7f7088a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
@@ -163,7 +163,7 @@
Text(
text = data,
color = MaterialTheme.colorScheme.onSurfaceVariant,
- style = MaterialTheme.typography.titleMedium,
+ style = MaterialTheme.typography.titleSmall,
)
}
subTitle()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index e0e9b95..c6e13a1 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -16,19 +16,21 @@
package com.android.settingslib.spa.widget.scaffold
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.TabRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import com.android.settingslib.spa.framework.compose.HorizontalPager
-import com.android.settingslib.spa.framework.compose.rememberPagerState
import com.android.settingslib.spa.framework.theme.SettingsDimension
import kotlin.math.absoluteValue
import kotlinx.coroutines.launch
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit) {
check(titles.isNotEmpty())
@@ -52,7 +54,7 @@
SettingsTab(
title = title,
selected = pagerState.currentPage == page,
- currentPageOffset = pagerState.currentPageOffset.absoluteValue,
+ currentPageOffset = pagerState.currentPageOffsetFraction.absoluteValue,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(page)
@@ -62,7 +64,7 @@
}
}
- HorizontalPager(count = titles.size, state = pagerState) { page ->
+ HorizontalPager(pageCount = titles.size, state = pagerState) { page ->
content(page)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 64a9c73..f0df9a6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -23,8 +23,8 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.ArrowDropDown
-import androidx.compose.material.icons.outlined.ArrowDropUp
+import androidx.compose.material.icons.outlined.ExpandLess
+import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
@@ -76,8 +76,8 @@
SpinnerText(options.find { it.id == selectedId })
Icon(
imageVector = when {
- expanded -> Icons.Outlined.ArrowDropUp
- else -> Icons.Outlined.ArrowDropDown
+ expanded -> Icons.Outlined.ExpandLess
+ else -> Icons.Outlined.ExpandMore
},
contentDescription = null,
)
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
index 379b9a7..b139f28 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
@@ -115,7 +115,7 @@
fun testGetEntryPath() {
SpaEnvironmentFactory.reset(spaEnvironment)
assertThat(
- entryRepository.getEntryPathWithDisplayName(
+ entryRepository.getEntryPathWithLabel(
genEntryId("Layer2Entry1", SppLayer2.createSettingsPage())
)
).containsExactly("Layer2Entry1", "INJECT_SppLayer2", "INJECT_SppLayer1", "ROOT_SppHome")
@@ -129,7 +129,7 @@
).containsExactly("entryTitle", "SppLayer2", "TitleLayer1", "TitleHome").inOrder()
assertThat(
- entryRepository.getEntryPathWithDisplayName(
+ entryRepository.getEntryPathWithLabel(
genEntryId(
"INJECT",
SppLayer1.createSettingsPage(),
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index 5754c9b..ce34979 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -68,7 +68,7 @@
val owner = createSettingsPage("mySpp")
val entry = SettingsEntryBuilder.create(owner, "myEntry").build()
assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry.displayName).isEqualTo("myEntry")
+ assertThat(entry.label).isEqualTo("myEntry")
assertThat(entry.owner.sppName).isEqualTo("mySpp")
assertThat(entry.owner.displayName).isEqualTo("mySpp")
assertThat(entry.fromPage).isNull()
@@ -87,14 +87,14 @@
val entryFrom =
SettingsEntryBuilder.createLinkFrom("myEntry", owner).setLink(toPage = toPage).build()
assertThat(entryFrom.id).isEqualTo(genEntryId("myEntry", owner, owner, toPage))
- assertThat(entryFrom.displayName).isEqualTo("myEntry")
+ assertThat(entryFrom.label).isEqualTo("myEntry")
assertThat(entryFrom.fromPage!!.sppName).isEqualTo("mySpp")
assertThat(entryFrom.toPage!!.sppName).isEqualTo("toSpp")
val entryTo =
SettingsEntryBuilder.createLinkTo("myEntry", owner).setLink(fromPage = fromPage).build()
assertThat(entryTo.id).isEqualTo(genEntryId("myEntry", owner, fromPage, owner))
- assertThat(entryTo.displayName).isEqualTo("myEntry")
+ assertThat(entryTo.label).isEqualTo("myEntry")
assertThat(entryTo.fromPage!!.sppName).isEqualTo("fromSpp")
assertThat(entryTo.toPage!!.sppName).isEqualTo("mySpp")
}
@@ -108,7 +108,7 @@
INJECT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
- assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
+ assertThat(entryInject.label).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
assertThat(entryInject.fromPage).isNull()
assertThat(entryInject.toPage).isNotNull()
}
@@ -122,7 +122,7 @@
ROOT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
- assertThat(entryInject.displayName).isEqualTo("myRootEntry")
+ assertThat(entryInject.label).isEqualTo("myRootEntry")
assertThat(entryInject.fromPage).isNull()
assertThat(entryInject.toPage).isNotNull()
}
@@ -133,14 +133,14 @@
val owner = createSettingsPage("SppHome")
val entryBuilder =
SettingsEntryBuilder.create(owner, "myEntry")
- .setDisplayName("myEntryDisplay")
+ .setLabel("myEntryDisplay")
.setIsSearchDataDynamic(false)
.setHasMutableStatus(true)
.setSearchDataFn { null }
.setSliceDataFn { _, _ -> null }
val entry = entryBuilder.build()
assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entry.label).isEqualTo("myEntryDisplay")
assertThat(entry.fromPage).isNull()
assertThat(entry.toPage).isNull()
assertThat(entry.isAllowSearch).isTrue()
@@ -152,14 +152,14 @@
val ownerDisabled = createSettingsPage("SppDisabled")
val entryBuilderDisabled =
SettingsEntryBuilder.create(ownerDisabled, "myEntry")
- .setDisplayName("myEntryDisplay")
+ .setLabel("myEntryDisplay")
.setIsSearchDataDynamic(false)
.setHasMutableStatus(true)
.setSearchDataFn { null }
.setSliceDataFn { _, _ -> null }
val entryDisabled = entryBuilderDisabled.build()
assertThat(entryDisabled.id).isEqualTo(genEntryId("myEntry", ownerDisabled))
- assertThat(entryDisabled.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entryDisabled.label).isEqualTo("myEntryDisplay")
assertThat(entryDisabled.fromPage).isNull()
assertThat(entryDisabled.toPage).isNull()
assertThat(entryDisabled.isAllowSearch).isFalse()
@@ -175,7 +175,7 @@
SpaEnvironmentFactory.reset()
val entry3 = entryBuilder.build()
assertThat(entry3.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry3.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entry3.label).isEqualTo("myEntryDisplay")
assertThat(entry3.fromPage).isNull()
assertThat(entry3.toPage).isNull()
assertThat(entry3.isAllowSearch).isFalse()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
index 007d08b..00d2314 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
@@ -63,6 +63,11 @@
pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
)
immutableStatus.checkValue(
+ QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ immutableStatus.checkValue(
QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
@@ -75,6 +80,11 @@
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
mutableStatus.checkValue(
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
+ mutableStatus.checkValue(
QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
)
@@ -85,6 +95,11 @@
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
mutableStatus.checkValue(
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
+ mutableStatus.checkValue(
QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
}
@@ -102,6 +117,11 @@
pageOwner.getEntryId("SearchStaticWithNoStatus")
)
staticData.checkValue(
+ QueryEnum.SEARCH_STATIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+ )
+ staticData.checkValue(
QueryEnum.SEARCH_STATIC_DATA_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
)
staticData.checkValue(
@@ -139,6 +159,11 @@
ColumnEnum.ENTRY_ID,
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
+ staticData.checkValue(
+ QueryEnum.SEARCH_STATIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
val dynamicData = searchProvider.querySearchDynamicData()
Truth.assertThat(dynamicData.count).isEqualTo(2)
@@ -148,6 +173,11 @@
ColumnEnum.ENTRY_ID,
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
+ dynamicData.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
dynamicData.moveToNext()
dynamicData.checkValue(
@@ -157,6 +187,11 @@
)
dynamicData.checkValue(
QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ dynamicData.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
ColumnEnum.SEARCH_KEYWORD,
listOf("kw1", "kw2").toString()
)
@@ -175,6 +210,11 @@
pageOwner.getEntryId("SearchStaticWithNoStatus")
)
staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+ )
+ staticRow.checkValue(
QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
)
staticRow.checkValue(
@@ -223,6 +263,11 @@
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
+ dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
)
@@ -233,6 +278,11 @@
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
+ dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
@@ -245,6 +295,11 @@
)
dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
ColumnEnum.SEARCH_KEYWORD,
listOf("kw1", "kw2").toString()
)
@@ -271,3 +326,7 @@
private fun SettingsPage.getEntryId(name: String): String {
return SettingsEntryBuilder.create(this, name).build().id
}
+
+private fun SettingsPage.getEntryLabel(name: String): String {
+ return SettingsEntryBuilder.create(this, name).build().label
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
index 14cb698f..e37288ab 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
@@ -81,7 +81,7 @@
val entryList = appInfoPageProvider.buildEntry(null)
assertThat(entryList).hasSize(1)
- assertThat(entryList[0].displayName).isEqualTo("AllowControl")
+ assertThat(entryList[0].label).isEqualTo("AllowControl")
}
@Test
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index 9e86567..eca1165 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -23,6 +23,6 @@
apex_available: [
"//apex_available:platform",
"com.android.cellbroadcast",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/TwoTargetPreference/Android.bp b/packages/SettingsLib/TwoTargetPreference/Android.bp
index e9c6aed..a3e50a9 100644
--- a/packages/SettingsLib/TwoTargetPreference/Android.bp
+++ b/packages/SettingsLib/TwoTargetPreference/Android.bp
@@ -23,6 +23,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index dc88304..644e990 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/Utils/Android.bp
@@ -26,6 +26,6 @@
"com.android.adservices",
"com.android.permission",
"com.android.cellbroadcast",
- "com.android.healthconnect",
+ "com.android.healthfitness",
],
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 6641db1..91b852a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -235,7 +235,7 @@
/**
* @return whether high quality audio is enabled or not
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
@@ -287,7 +287,7 @@
* @param device to get codec label from
* @return the label associated with the device codec
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index e0588ee..2555e2b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -34,6 +34,8 @@
import com.android.settingslib.R;
+import java.util.Optional;
+
/**
* Stores and computes some battery information.
*/
@@ -52,11 +54,12 @@
public final int health;
public final int maxChargingWattage;
public final boolean present;
+ public final Optional<Boolean> incompatibleCharger;
- public static BatteryStatus create(Context context) {
+ public static BatteryStatus create(Context context, boolean incompatibleCharger) {
final Intent batteryChangedIntent = BatteryUtils.getBatteryIntent(context);
return batteryChangedIntent == null
- ? null : new BatteryStatus(batteryChangedIntent);
+ ? null : new BatteryStatus(batteryChangedIntent, incompatibleCharger);
}
public BatteryStatus(int status, int level, int plugged, int health,
@@ -67,14 +70,25 @@
this.health = health;
this.maxChargingWattage = maxChargingWattage;
this.present = present;
+ this.incompatibleCharger = Optional.empty();
}
+
public BatteryStatus(Intent batteryChangedIntent) {
+ this(batteryChangedIntent, Optional.empty());
+ }
+
+ public BatteryStatus(Intent batteryChangedIntent, boolean incompatibleCharger) {
+ this(batteryChangedIntent, Optional.of(incompatibleCharger));
+ }
+
+ private BatteryStatus(Intent batteryChangedIntent, Optional<Boolean> incompatibleCharger) {
status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
level = getBatteryLevel(batteryChangedIntent);
health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true);
+ this.incompatibleCharger = incompatibleCharger;
final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT,
-1);
@@ -95,10 +109,7 @@
/** Determine whether the device is plugged. */
public boolean isPluggedIn() {
- return plugged == BatteryManager.BATTERY_PLUGGED_AC
- || plugged == BatteryManager.BATTERY_PLUGGED_USB
- || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
- || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
+ return isPluggedIn(plugged);
}
/** Determine whether the device is plugged in (USB, power). */
@@ -190,4 +201,17 @@
? -1 /*invalid battery level*/
: Math.round((level / (float) scale) * 100f);
}
+
+ /** Whether the device is plugged or not. */
+ public static boolean isPluggedIn(Intent batteryChangedIntent) {
+ return isPluggedIn(batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0));
+ }
+
+ /** Whether the device is plugged or not. */
+ public static boolean isPluggedIn(int plugged) {
+ return plugged == BatteryManager.BATTERY_PLUGGED_AC
+ || plugged == BatteryManager.BATTERY_PLUGGED_USB
+ || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
+ || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f1413e5..7abace03 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -97,7 +97,6 @@
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.provider.Settings.SetAllResult;
-import android.provider.UpdatableDeviceConfigServiceReadiness;
import android.provider.settings.validators.SystemSettingsValidators;
import android.provider.settings.validators.Validator;
import android.text.TextUtils;
@@ -419,16 +418,10 @@
startWatchingUserRestrictionChanges();
});
ServiceManager.addService("settings", new SettingsService(this));
- addDeviceConfigServiceIfNeeded();
+ ServiceManager.addService("device_config", new DeviceConfigService(this));
return true;
}
- private void addDeviceConfigServiceIfNeeded() {
- if (!UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
- ServiceManager.addService("device_config", new DeviceConfigService(this));
- }
- }
-
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index f4cef84..51f507c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -55,6 +55,9 @@
<!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited. -->
<string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging optimized to protect battery</string>
+ <!-- When the lock screen is showing and the phone plugged in with incompatible charger. -->
+ <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Incompatible charging</string>
+
<!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock. This is shown in small font at the bottom. -->
<string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
new file mode 100644
index 0000000..1b12e74
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
@@ -0,0 +1,25 @@
+<!--
+ 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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?android:attr/textColorSecondary">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M39.8,41.95 L26.65,28.8Q25.15,30.1 23.15,30.825Q21.15,31.55 18.9,31.55Q13.5,31.55 9.75,27.8Q6,24.05 6,18.75Q6,13.45 9.75,9.7Q13.5,5.95 18.85,5.95Q24.15,5.95 27.875,9.7Q31.6,13.45 31.6,18.75Q31.6,20.9 30.9,22.9Q30.2,24.9 28.8,26.65L42,39.75ZM18.85,28.55Q22.9,28.55 25.75,25.675Q28.6,22.8 28.6,18.75Q28.6,14.7 25.75,11.825Q22.9,8.95 18.85,8.95Q14.75,8.95 11.875,11.825Q9,14.7 9,18.75Q9,22.8 11.875,25.675Q14.75,28.55 18.85,28.55Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
new file mode 100644
index 0000000..e3b1ab2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
@@ -0,0 +1,25 @@
+<!--
+ 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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/textColorSecondary">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="@android:color/white"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
new file mode 100644
index 0000000..a21489c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="16dp"/>
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
new file mode 100644
index 0000000..2ff32b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="16dp"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
new file mode 100644
index 0000000..6ce3eae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackground"/>
+ <corners android:topLeftRadius="16dp"
+ android:topRightRadius="16dp"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_search_background.xml b/packages/SystemUI/res/drawable/shortcut_search_background.xml
new file mode 100644
index 0000000..66fc191
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_search_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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
+ -->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/font_scaling_dialog.xml b/packages/SystemUI/res/layout/font_scaling_dialog.xml
new file mode 100644
index 0000000..27c1e9d
--- /dev/null
+++ b/packages/SystemUI/res/layout/font_scaling_dialog.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+<com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/font_scaling_slider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ app:max="6"
+ app:progress="0"
+ app:iconStartContentDescription="@string/font_scaling_smaller"
+ app:iconEndContentDescription="@string/font_scaling_larger"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
new file mode 100644
index 0000000..530e46e
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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
+ -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="0dp"
+ style="@style/ShortcutHorizontalDivider" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
new file mode 100644
index 0000000..a037cb2
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:scaleType="fitXY"
+ android:tint="?android:attr/textColorPrimary"
+ style="@style/ShortcutItemBackground" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
new file mode 100644
index 0000000..12b4e15
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginStart="@dimen/ksh_item_margin_start"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="false"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
new file mode 100644
index 0000000..727f2c1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:text="+"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"
+ android:textAllCaps="true"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
new file mode 100644
index 0000000..00ef947
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:text="|"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"
+ android:textAllCaps="true"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
new file mode 100644
index 0000000..8a66f50
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@drawable/shortcut_dialog_bg"
+ android:layout_width="@dimen/ksh_layout_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/shortcut_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="40dp"
+ android:layout_gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/keyboard_shortcut_search_list_title"/>
+
+ <FrameLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <EditText
+ android:id="@+id/keyboard_shortcuts_search"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp"
+ android:layout_marginStart="49dp"
+ android:layout_marginEnd="49dp"
+ android:padding="16dp"
+ android:background="@drawable/shortcut_search_background"
+ android:drawableStart="@drawable/ic_shortcutlist_search"
+ android:drawablePadding="15dp"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:inputType="text"
+ android:textDirection="locale"
+ android:textAlignment="viewStart"
+ android:hint="@string/keyboard_shortcut_search_list_hint"
+ android:textColorHint="?android:attr/textColorTertiary" />
+
+ <ImageView
+ android:id="@+id/keyboard_shortcuts_search_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp"
+ android:layout_marginEnd="49dp"
+ android:padding="16dp"
+ android:contentDescription="@string/keyboard_shortcut_clear_text"
+ android:src="@drawable/ic_shortcutlist_search_button_cancel" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="37dp"/>
+
+ <Button
+ android:id="@+id/shortcut_system"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_system"/>
+
+ <Button
+ android:id="@+id/shortcut_input"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_input"/>
+
+ <Button
+ android:id="@+id/shortcut_open_apps"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_open_apps"/>
+
+ <Button
+ android:id="@+id/shortcut_specific_app"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_current_app"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/shortcut_search_no_result"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="50dp"
+ android:layout_gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/keyboard_shortcut_search_list_no_result"/>
+
+ <ScrollView
+ android:id="@+id/keyboard_shortcuts_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="25dp"
+ android:layout_marginEnd="25dp">
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+ </ScrollView>
+ <!-- Required for stretching to full available height when the items in the scroll view
+ occupy less space then the full height -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
index f20b582..52d1d4f 100644
--- a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
+++ b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
@@ -1,41 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2023 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.
- -->
+ Copyright (C) 2023 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.
+ -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/seekbar_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- tools:parentTag="android.widget.LinearLayout">
+ android:id="@+id/seekbar_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ tools:parentTag="android.widget.LinearLayout">
- <ImageView
- android:id="@+id/icon_start"
- android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:adjustViewBounds="true"
- android:focusable="true"
- android:src="@drawable/ic_remove"
- android:tint="?android:attr/textColorPrimary"
- android:tintMode="src_in" />
+ <FrameLayout
+ android:id="@+id/icon_start_frame"
+ android:layout_width="@dimen/min_clickable_item_size"
+ android:layout_height="@dimen/min_clickable_item_size"
+ android:clipChildren="false"
+ android:focusable="true" >
+ <ImageView
+ android:id="@+id/icon_start"
+ android:layout_width="@dimen/seekbar_icon_size"
+ android:layout_height="@dimen/seekbar_icon_size"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:adjustViewBounds="true"
+ android:focusable="false"
+ android:src="@drawable/ic_remove"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in" />
+ </FrameLayout>
<SeekBar
android:id="@+id/seekbar"
@@ -45,16 +51,23 @@
android:layout_gravity="center_vertical"
android:layout_weight="1" />
- <ImageView
- android:id="@+id/icon_end"
- android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:adjustViewBounds="true"
- android:focusable="true"
- android:src="@drawable/ic_add"
- android:tint="?android:attr/textColorPrimary"
- android:tintMode="src_in" />
+ <FrameLayout
+ android:id="@+id/icon_end_frame"
+ android:layout_width="@dimen/min_clickable_item_size"
+ android:layout_height="@dimen/min_clickable_item_size"
+ android:clipChildren="false"
+ android:focusable="true" >
+ <ImageView
+ android:id="@+id/icon_end"
+ android:layout_width="@dimen/seekbar_icon_size"
+ android:layout_height="@dimen/seekbar_icon_size"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:adjustViewBounds="true"
+ android:focusable="false"
+ android:src="@drawable/ic_add"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in" />
+ </FrameLayout>
</merge>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e2fdf16..c6cc0bc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -118,6 +118,7 @@
<color name="ksh_application_group_color">#fff44336</color>
<color name="ksh_key_item_color">@color/material_grey_600</color>
<color name="ksh_key_item_background">@color/material_grey_100</color>
+ <color name="ksh_key_item_new_background">@color/transparent</color>
<color name="instant_apps_color">#ff4d5a64</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 36172ca..4afe9d5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1183,8 +1183,9 @@
<dimen name="magnification_setting_image_button_padding_horizontal">24dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_vertical">16dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
- <dimen name="magnification_setting_seekbar_icon_size">24dp</dimen>
+ <!-- Seekbar with icon buttons -->
+ <dimen name="seekbar_icon_size">24dp</dimen>
<!-- How far from the right edge of the screen you need to drag the window before the button
repositions to the other side. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 85edbec..435a866 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1700,34 +1700,105 @@
<string name="keyboard_shortcut_group_system">System</string>
<!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
<string name="keyboard_shortcut_group_system_home">Home</string>
- <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the recents screen. -->
<string name="keyboard_shortcut_group_system_recents">Recents</string>
- <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
+ <!-- User visible title for the keyboard shortcut that triggers the back action. -->
<string name="keyboard_shortcut_group_system_back">Back</string>
- <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+ <!-- User visible title for the keyboard shortcut that triggers the notification shade. -->
<string name="keyboard_shortcut_group_system_notifications">Notifications</string>
- <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+ <!-- User visible title for the keyboard shortcut that triggers the keyboard shortcuts helper. -->
<string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
- <!-- User visible title for the the keyboard shortcut that switches to the next hardware keyboard layout. [CHAR LIMIT=30] -->
+ <!-- User visible title for the keyboard shortcut that switches to the next hardware keyboard layout. -->
<string name="keyboard_shortcut_group_system_switch_input">Switch keyboard layout</string>
- <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+ <!-- Content description for the clear text button in shortcut search list. [CHAR LIMIT=NONE] -->
+ <string name="keyboard_shortcut_clear_text">Clear text</string>
+ <!-- The title for keyboard shortcut search list [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_title">Shortcuts</string>
+ <!-- The hint for keyboard shortcut search list [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_hint">Search shortcuts</string>
+ <!-- The description for no shortcuts results [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_no_result">No shortcuts found</string>
+ <!-- The title of system category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_system">System</string>
+ <!-- The title of input category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_input">Input</string>
+ <!-- The title of open apps category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_open_apps">Open apps</string>
+ <!-- The title of current app category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_current_app">Current app</string>
+
+ <!-- User visible title for the keyboard shortcut that triggers the notification shade. [CHAR LIMIT=70] -->
+ <string name="group_system_access_notification_shade">Access notification shade</string>
+ <!-- User visible title for the keyboard shortcut that takes a full screenshot. [CHAR LIMIT=70] -->
+ <string name="group_system_full_screenshot">Take a full screenshot</string>
+ <!-- User visible title for the keyboard shortcut that access list of system / apps shortcuts. [CHAR LIMIT=70] -->
+ <string name="group_system_access_system_app_shortcuts">Access list of system / apps shortcuts</string>
+ <!-- User visible title for the keyboard shortcut that goes back to previous state. [CHAR LIMIT=70] -->
+ <string name="group_system_go_back">Back: go back to previous state (back button)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the home screen. [CHAR LIMIT=70] -->
+ <string name="group_system_access_home_screen">Access home screen</string>
+ <!-- User visible title for the keyboard shortcut that triggers overview of open apps. [CHAR LIMIT=70] -->
+ <string name="group_system_overview_open_apps">Overview of open apps</string>
+ <!-- User visible title for the keyboard shortcut that cycles through recent apps (forward). [CHAR LIMIT=70] -->
+ <string name="group_system_cycle_forward">Cycle through recent apps (forward)</string>
+ <!-- User visible title for the keyboard shortcut that cycles through recent apps (back). [CHAR LIMIT=70] -->
+ <string name="group_system_cycle_back">Cycle through recent apps (back)</string>
+ <!-- User visible title for the keyboard shortcut that accesses list of all apps and search. [CHAR LIMIT=70] -->
+ <string name="group_system_access_all_apps_search">Access list of all apps and search (i.e. Search/Launcher)</string>
+ <!-- User visible title for the keyboard shortcut that hides and (re)showes taskbar. [CHAR LIMIT=70] -->
+ <string name="group_system_hide_reshow_taskbar">Hide and (re)show taskbar</string>
+ <!-- User visible title for the keyboard shortcut that accesses system settings. [CHAR LIMIT=70] -->
+ <string name="group_system_access_system_settings">Access system settings</string>
+ <!-- User visible title for the keyboard shortcut that accesses Google Assistant. [CHAR LIMIT=70] -->
+ <string name="group_system_access_google_assistant">Access Google Assistant</string>
+ <!-- User visible title for the keyboard shortcut that locks screen. [CHAR LIMIT=70] -->
+ <string name="group_system_lock_screen">Lock screen</string>
+ <!-- User visible title for the keyboard shortcut that pulls up Notes app for quick memo. [CHAR LIMIT=70] -->
+ <string name="group_system_quick_memo">Pull up Notes app for quick memo</string>
+
+ <!-- User visible title for the system multitasking keyboard shortcuts list. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_system_multitasking">System multitasking</string>
+ <!-- User visible title for the keyboard shortcut that enters split screen with current app to RHS [CHAR LIMIT=70] -->
+ <string name="system_multitasking_rhs">Enter Split screen with current app to RHS</string>
+ <!-- User visible title for the keyboard shortcut that enters split screen with current app to LHS [CHAR LIMIT=70] -->
+ <string name="system_multitasking_lhs">Enter Split screen with current app to LHS</string>
+ <!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_full_screen">Switch from Split screen to full screen</string>
+ <!-- User visible title for the keyboard shortcut that replaces an app from one to another during split screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_replace">During Split screen: replace an app from one to another</string>
+
+ <!-- User visible title for the input keyboard shortcuts list. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_input">Input</string>
+ <!-- User visible title for the keyboard shortcut that switches input language (next language). [CHAR LIMIT=70] -->
+ <string name="input_switch_input_language_next">Switch input language (next language)</string>
+ <!-- User visible title for the keyboard shortcut that switches input language (previous language). [CHAR LIMIT=70] -->
+ <string name="input_switch_input_language_previous">Switch input language (previous language)</string>
+ <!-- User visible title for the keyboard shortcut that accesses emoji. [CHAR LIMIT=70] -->
+ <string name="input_access_emoji">Access emoji</string>
+ <!-- User visible title for the keyboard shortcut that accesses voice typing. [CHAR LIMIT=70] -->
+ <string name="input_access_voice_typing">Access voice typing</string>
+
+ <!-- User visible title for the system-wide applications keyboard shortcuts list. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications">Applications</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the assist app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_assist">Assist</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
- <string name="keyboard_shortcut_group_applications_browser">Browser</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the browser app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_browser">Browser (Chrome as default)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
- <string name="keyboard_shortcut_group_applications_email">Email</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the email app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_email">Email (Gmail as default)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_sms">SMS</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the music app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_music">Music</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
- <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calculator app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_calculator">Calculator</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the maps app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_maps">Maps</string>
<!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
<string name="volume_and_do_not_disturb">Do Not Disturb</string>
@@ -2233,6 +2304,14 @@
<!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
<string name="inattentive_sleep_warning_title">Standby</string>
+ <!-- Font scaling -->
+ <!-- Font scaling: Quick Settings dialog title [CHAR LIMIT=30] -->
+ <string name="font_scaling_dialog_title">Font Size</string>
+ <!-- Content Description for the icon button to make fonts smaller. [CHAR LIMIT=30] -->
+ <string name="font_scaling_smaller">Make smaller</string>
+ <!-- Content Description for the icon button to make fonts larger. [CHAR LIMIT=30] -->
+ <string name="font_scaling_larger">Make larger</string>
+
<!-- Window Magnification strings -->
<!-- Title for Magnification Window [CHAR LIMIT=NONE] -->
<string name="magnification_window_title">Magnification Window</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9398c89..2cd2173 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1375,4 +1375,23 @@
<item name="android:lineHeight">@dimen/magnification_setting_button_line_height</item>
<item name="android:textAlignment">center</item>
</style>
+
+ <style name="ShortCutButton" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/shortcut_button_colored</item>
+ <item name="android:stateListAnimator">@null</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:padding">4dp</item>
+ <item name="android:textColor">?androidprv:attr/textColorSecondary</item>
+ </style>
+
+ <style name="ShortcutHorizontalDivider">
+ <item name="android:layout_width">120dp</item>
+ <item name="android:layout_height">1dp</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:background">?android:attr/dividerHorizontal</item>
+ </style>
+
+ <style name="ShortcutItemBackground">
+ <item name="android:background">@color/ksh_key_item_new_background</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9f1c382..5b628f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -102,6 +102,7 @@
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.usb.UsbManager;
import android.nfc.NfcAdapter;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -138,6 +139,7 @@
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.fuelgauge.BatteryStatus;
+import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
@@ -329,6 +331,8 @@
// Battery status
@VisibleForTesting
BatteryStatus mBatteryStatus;
+ @VisibleForTesting
+ boolean mIncompatibleCharger;
private StrongAuthTracker mStrongAuthTracker;
@@ -1572,10 +1576,20 @@
MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
-
+ // Clear incompatible charger state when device is unplugged.
+ if (!BatteryStatus.isPluggedIn(intent)) {
+ mIncompatibleCharger = false;
+ }
final Message msg = mHandler.obtainMessage(
- MSG_BATTERY_UPDATE, new BatteryStatus(intent));
+ MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger));
mHandler.sendMessage(msg);
+ } else if (UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED.equals(action)) {
+ mIncompatibleCharger = Utils.containsIncompatibleChargers(context, TAG);
+ BatteryStatus batteryStatus = BatteryStatus.create(context, mIncompatibleCharger);
+ if (batteryStatus != null) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_BATTERY_UPDATE, batteryStatus));
+ }
} else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
SimData args = SimData.fromIntent(intent);
// ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
@@ -2251,6 +2265,7 @@
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler);
// Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the
// listener now with the service state from the default sub.
@@ -3527,8 +3542,6 @@
final boolean wasPluggedIn = old.isPluggedIn();
final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn
&& (old.status != current.status);
- final boolean nowPresent = current.present;
- final boolean wasPresent = old.present;
// change in plug state is always interesting
if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
@@ -3545,8 +3558,13 @@
return true;
}
- // Battery either showed up or disappeared
- if (wasPresent != nowPresent) {
+ // change in battery is present or not
+ if (old.present != current.present) {
+ return true;
+ }
+
+ // change in the incompatible charger
+ if (!old.incompatibleCharger.equals(current.incompatibleCharger)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
new file mode 100644
index 0000000..54f933a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 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.accessibility.fontscaling
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.os.Bundle
+import android.provider.Settings
+import android.view.LayoutInflater
+import android.widget.Button
+import android.widget.SeekBar
+import android.widget.SeekBar.OnSeekBarChangeListener
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
+
+/** The Dialog that contains a seekbar for changing the font size. */
+class FontScalingDialog(context: Context, private val systemSettings: SystemSettings) :
+ SystemUIDialog(context) {
+ private val strEntryValues: Array<String> =
+ context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+ private lateinit var title: TextView
+ private lateinit var doneButton: Button
+ private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView
+
+ private val configuration: Configuration =
+ Configuration(context.getResources().getConfiguration())
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setTitle(R.string.font_scaling_dialog_title)
+ setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null))
+ setPositiveButton(
+ R.string.quick_settings_done,
+ /* onClick = */ null,
+ /* dismissOnClick = */ true
+ )
+ super.onCreate(savedInstanceState)
+
+ title = requireViewById(com.android.internal.R.id.alertTitle)
+ doneButton = requireViewById(com.android.internal.R.id.button1)
+ seekBarWithIconButtonsView = requireViewById(R.id.font_scaling_slider)
+
+ seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
+ seekBarWithIconButtonsView.setProgress(fontSizeValueToIndex(currentScale))
+
+ seekBarWithIconButtonsView.setOnSeekBarChangeListener(
+ object : OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[progress])
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {
+ // Do nothing
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {
+ // Do nothing
+ }
+ }
+ )
+ doneButton.setOnClickListener { dismiss() }
+ }
+
+ private fun fontSizeValueToIndex(value: Float): Int {
+ var lastValue = strEntryValues[0].toFloat()
+ for (i in 1 until strEntryValues.size) {
+ val thisValue = strEntryValues[i].toFloat()
+ if (value < lastValue + (thisValue - lastValue) * .5f) {
+ return i - 1
+ }
+ lastValue = thisValue
+ }
+ return strEntryValues.size - 1
+ }
+
+ override fun onConfigurationChanged(configuration: Configuration) {
+ super.onConfigurationChanged(configuration)
+
+ val configDiff = configuration.diff(this.configuration)
+ this.configuration.setTo(configuration)
+
+ if (configDiff and ActivityInfo.CONFIG_FONT_SCALE != 0) {
+ title.post {
+ title.setTextAppearance(R.style.TextAppearance_Dialog_Title)
+ doneButton.setTextAppearance(R.style.Widget_Dialog_Button)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index ae6a08f..a2077a3 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -37,6 +38,8 @@
private static final int DEFAULT_SEEKBAR_MAX = 6;
private static final int DEFAULT_SEEKBAR_PROGRESS = 0;
+ private ViewGroup mIconStartFrame;
+ private ViewGroup mIconEndFrame;
private ImageView mIconStart;
private ImageView mIconEnd;
private SeekBar mSeekbar;
@@ -62,6 +65,8 @@
LayoutInflater.from(context).inflate(
R.layout.seekbar_with_icon_buttons, this, /* attachToRoot= */ true);
+ mIconStartFrame = findViewById(R.id.icon_start_frame);
+ mIconEndFrame = findViewById(R.id.icon_end_frame);
mIconStart = findViewById(R.id.icon_start);
mIconEnd = findViewById(R.id.icon_end);
mSeekbar = findViewById(R.id.seekbar);
@@ -80,24 +85,22 @@
mSeekbar.setMax(max);
setProgress(progress);
- int iconStartContentDescriptionId = typedArray.getResourceId(
+ int iconStartFrameContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconStartContentDescription,
/* defValue= */ 0);
- int iconEndContentDescriptionId = typedArray.getResourceId(
+ int iconEndFrameContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconEndContentDescription,
/* defValue= */ 0);
- if (iconStartContentDescriptionId != 0) {
+ if (iconStartFrameContentDescriptionId != 0) {
final String contentDescription =
- context.getString(iconStartContentDescriptionId);
- mIconStart.setContentDescription(contentDescription);
+ context.getString(iconStartFrameContentDescriptionId);
+ mIconStartFrame.setContentDescription(contentDescription);
}
- if (iconEndContentDescriptionId != 0) {
+ if (iconEndFrameContentDescriptionId != 0) {
final String contentDescription =
- context.getString(iconEndContentDescriptionId);
- mIconEnd.setContentDescription(contentDescription);
+ context.getString(iconEndFrameContentDescriptionId);
+ mIconEndFrame.setContentDescription(contentDescription);
}
-
- typedArray.recycle();
} else {
mSeekbar.setMax(DEFAULT_SEEKBAR_MAX);
setProgress(DEFAULT_SEEKBAR_PROGRESS);
@@ -109,7 +112,7 @@
final int progress = mSeekbar.getProgress();
if (progress > 0) {
mSeekbar.setProgress(progress - 1);
- setIconViewEnabled(mIconStart, mSeekbar.getProgress() > 0);
+ setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0);
}
});
@@ -117,13 +120,15 @@
final int progress = mSeekbar.getProgress();
if (progress < mSeekbar.getMax()) {
mSeekbar.setProgress(progress + 1);
- setIconViewEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
+ setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
}
});
}
- private static void setIconViewEnabled(View iconView, boolean enabled) {
+ private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
iconView.setEnabled(enabled);
+ final ViewGroup iconFrame = (ViewGroup) iconView.getParent();
+ iconFrame.setEnabled(enabled);
}
/**
@@ -141,12 +146,22 @@
* Icon End will need to be enabled when the seekbar progress is less than Max.
*/
private void updateIconViewIfNeeded(int progress) {
- setIconViewEnabled(mIconStart, progress > 0);
- setIconViewEnabled(mIconEnd, progress < mSeekbar.getMax());
+ setIconViewAndFrameEnabled(mIconStart, progress > 0);
+ setIconViewAndFrameEnabled(mIconEnd, progress < mSeekbar.getMax());
+ }
+
+ /**
+ * Sets max to the seekbar in the layout.
+ */
+ public void setMax(int max) {
+ mSeekbar.setMax(max);
}
/**
* Sets progress to the seekbar in the layout.
+ * If the progress is smaller than or equals to 0, the IconStart will be disabled. If the
+ * progress is larger than or equals to Max, the IconEnd will be disabled. The seekbar progress
+ * will be constrained in {@link SeekBar}.
*/
public void setProgress(int progress) {
mSeekbar.setProgress(progress);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index d0c5007..fadabb4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -47,6 +47,7 @@
import com.android.systemui.shade.ShadeControllerImpl;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyboardShortcutsModule;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -100,7 +101,8 @@
QSModule.class,
ReferenceScreenshotModule.class,
StartCentralSurfacesModule.class,
- VolumeModule.class
+ VolumeModule.class,
+ KeyboardShortcutsModule.class
})
public abstract class ReferenceSystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 4d8f89e..b9cd535 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -19,8 +19,12 @@
import android.os.Handler
import android.os.Looper
import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger
import com.android.systemui.R
+import com.android.systemui.accessibility.fontscaling.FontScalingDialog
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -30,6 +34,8 @@
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
import javax.inject.Inject
class FontScalingTile
@@ -42,7 +48,9 @@
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
- qsLogger: QSLogger
+ qsLogger: QSLogger,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val systemSettings: SystemSettings
) :
QSTileImpl<QSTile.State?>(
host,
@@ -54,7 +62,7 @@
activityStarter,
qsLogger
) {
- private val mIcon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
+ private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
override fun isAvailable(): Boolean {
return false
@@ -66,11 +74,24 @@
return state
}
- override fun handleClick(view: View?) {}
+ override fun handleClick(view: View?) {
+ mUiHandler.post {
+ val dialog: SystemUIDialog = FontScalingDialog(mContext, systemSettings)
+ if (view != null) {
+ dialogLaunchAnimator.showFromView(
+ dialog,
+ view,
+ DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
+ )
+ } else {
+ dialog.show()
+ }
+ }
+ }
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
- state?.icon = mIcon
+ state?.icon = icon
}
override fun getLongClickIntent(): Intent? {
@@ -80,4 +101,8 @@
override fun getTileLabel(): CharSequence {
return mContext.getString(R.string.quick_settings_font_scaling_label)
}
+
+ companion object {
+ private const val INTERACTION_JANK_TAG = "font_scaling"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
new file mode 100644
index 0000000..01e042b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -0,0 +1,1382 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.ContextThemeWrapper;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Contains functionality for handling keyboard shortcuts.
+ */
+public final class KeyboardShortcutListSearch {
+ private static final String TAG = KeyboardShortcutListSearch.class.getSimpleName();
+ private static final Object sLock = new Object();
+ @VisibleForTesting static KeyboardShortcutListSearch sInstance;
+
+ private static int SHORTCUT_SYSTEM_INDEX = 0;
+ private static int SHORTCUT_INPUT_INDEX = 1;
+ private static int SHORTCUT_OPENAPPS_INDEX = 2;
+ private static int SHORTCUT_SPECIFICAPP_INDEX = 3;
+
+ private WindowManager mWindowManager;
+ private EditText mSearchEditText;
+ private String mQueryString;
+ private int mCurrentCategoryIndex = 0;
+ private Map<Integer, Boolean> mKeySearchResultMap = new HashMap<>();
+
+ private List<List<KeyboardShortcutMultiMappingGroup>> mFullShortsGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mSpecificAppGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mSystemGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mInputGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mOpenAppsGroup = new ArrayList<>();
+
+ private ArrayList<Button> mFullButtonList = new ArrayList<>();
+ private Button mButtonSystem;
+ private Button mButtonInput;
+ private Button mButtonOpenApps;
+ private Button mButtonSpecificApp;
+ private ImageView mEditTextCancel;
+ private TextView mNoSearchResults;
+
+ private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
+ private final SparseArray<String> mModifierNames = new SparseArray<>();
+ private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
+ private final SparseArray<Drawable> mModifierDrawables = new SparseArray<>();
+ // Ordered list of modifiers that are supported. All values in this array must exist in
+ // mModifierNames.
+ private final int[] mModifierList = new int[] {
+ KeyEvent.META_META_ON, KeyEvent.META_CTRL_ON, KeyEvent.META_ALT_ON,
+ KeyEvent.META_SHIFT_ON, KeyEvent.META_SYM_ON, KeyEvent.META_FUNCTION_ON
+ };
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ @VisibleForTesting Context mContext;
+ private final IPackageManager mPackageManager;
+
+ @VisibleForTesting BottomSheetDialog mKeyboardShortcutsBottomSheetDialog;
+ private KeyCharacterMap mKeyCharacterMap;
+ private KeyCharacterMap mBackupKeyCharacterMap;
+
+ @VisibleForTesting
+ KeyboardShortcutListSearch(Context context, WindowManager windowManager) {
+ this.mContext = new ContextThemeWrapper(
+ context, android.R.style.Theme_DeviceDefault_Settings);
+ this.mPackageManager = AppGlobals.getPackageManager();
+ if (windowManager != null) {
+ this.mWindowManager = windowManager;
+ } else {
+ this.mWindowManager = mContext.getSystemService(WindowManager.class);
+ }
+ loadResources(context);
+ createHardcodedShortcuts();
+ }
+
+ private static KeyboardShortcutListSearch getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KeyboardShortcutListSearch(context, null);
+ }
+ return sInstance;
+ }
+
+ public static void show(Context context, int deviceId) {
+ MetricsLogger.visible(context,
+ MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+ synchronized (sLock) {
+ if (sInstance != null && !sInstance.mContext.equals(context)) {
+ dismiss();
+ }
+ getInstance(context).showKeyboardShortcuts(deviceId);
+ }
+ }
+
+ public static void toggle(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (isShowing()) {
+ dismiss();
+ } else {
+ show(context, deviceId);
+ }
+ }
+ }
+
+ public static void dismiss() {
+ synchronized (sLock) {
+ if (sInstance != null) {
+ MetricsLogger.hidden(sInstance.mContext,
+ MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+ sInstance.dismissKeyboardShortcuts();
+ sInstance = null;
+ }
+ }
+ }
+
+ private static boolean isShowing() {
+ return sInstance != null && sInstance.mKeyboardShortcutsBottomSheetDialog != null
+ && sInstance.mKeyboardShortcutsBottomSheetDialog.isShowing();
+ }
+
+ private void loadResources(Context context) {
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_BACK, context.getString(R.string.keyboard_key_back));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_UP, context.getString(R.string.keyboard_key_dpad_up));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_DOWN, context.getString(R.string.keyboard_key_dpad_down));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_LEFT, context.getString(R.string.keyboard_key_dpad_left));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_RIGHT, context.getString(R.string.keyboard_key_dpad_right));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_CENTER, context.getString(R.string.keyboard_key_dpad_center));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_PERIOD, ".");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_TAB, context.getString(R.string.keyboard_key_tab));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_SPACE, context.getString(R.string.keyboard_key_space));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_ENTER, context.getString(R.string.keyboard_key_enter));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DEL, context.getString(R.string.keyboard_key_backspace));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+ context.getString(R.string.keyboard_key_media_play_pause));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MEDIA_STOP, context.getString(R.string.keyboard_key_media_stop));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MEDIA_NEXT, context.getString(R.string.keyboard_key_media_next));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS,
+ context.getString(R.string.keyboard_key_media_previous));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_REWIND,
+ context.getString(R.string.keyboard_key_media_rewind));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD,
+ context.getString(R.string.keyboard_key_media_fast_forward));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_PAGE_UP, context.getString(R.string.keyboard_key_page_up));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_PAGE_DOWN, context.getString(R.string.keyboard_key_page_down));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_A,
+ context.getString(R.string.keyboard_key_button_template, "A"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_B,
+ context.getString(R.string.keyboard_key_button_template, "B"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_C,
+ context.getString(R.string.keyboard_key_button_template, "C"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_X,
+ context.getString(R.string.keyboard_key_button_template, "X"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Y,
+ context.getString(R.string.keyboard_key_button_template, "Y"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Z,
+ context.getString(R.string.keyboard_key_button_template, "Z"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L1,
+ context.getString(R.string.keyboard_key_button_template, "L1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R1,
+ context.getString(R.string.keyboard_key_button_template, "R1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L2,
+ context.getString(R.string.keyboard_key_button_template, "L2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R2,
+ context.getString(R.string.keyboard_key_button_template, "R2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_START,
+ context.getString(R.string.keyboard_key_button_template, "Start"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_SELECT,
+ context.getString(R.string.keyboard_key_button_template, "Select"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_MODE,
+ context.getString(R.string.keyboard_key_button_template, "Mode"));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BREAK, "Break");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MOVE_HOME, context.getString(R.string.keyboard_key_move_home));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MOVE_END, context.getString(R.string.keyboard_key_move_end));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_INSERT, context.getString(R.string.keyboard_key_insert));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F1, "F1");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F2, "F2");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F3, "F3");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F4, "F4");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F5, "F5");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F6, "F6");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F7, "F7");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F8, "F8");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F9, "F9");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F10, "F10");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F11, "F11");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F12, "F12");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MINUS, "-");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_GRAVE, "~");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_EQUALS, "=");
+
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_0,
+ context.getString(R.string.keyboard_key_numpad_template, "0"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_1,
+ context.getString(R.string.keyboard_key_numpad_template, "1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_2,
+ context.getString(R.string.keyboard_key_numpad_template, "2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_3,
+ context.getString(R.string.keyboard_key_numpad_template, "3"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_4,
+ context.getString(R.string.keyboard_key_numpad_template, "4"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_5,
+ context.getString(R.string.keyboard_key_numpad_template, "5"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_6,
+ context.getString(R.string.keyboard_key_numpad_template, "6"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_7,
+ context.getString(R.string.keyboard_key_numpad_template, "7"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_8,
+ context.getString(R.string.keyboard_key_numpad_template, "8"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_9,
+ context.getString(R.string.keyboard_key_numpad_template, "9"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE,
+ context.getString(R.string.keyboard_key_numpad_template, "/"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
+ context.getString(R.string.keyboard_key_numpad_template, "*"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
+ context.getString(R.string.keyboard_key_numpad_template, "-"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ADD,
+ context.getString(R.string.keyboard_key_numpad_template, "+"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DOT,
+ context.getString(R.string.keyboard_key_numpad_template, "."));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_COMMA,
+ context.getString(R.string.keyboard_key_numpad_template, ","));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ENTER,
+ context.getString(R.string.keyboard_key_numpad_template,
+ context.getString(R.string.keyboard_key_enter)));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_EQUALS,
+ context.getString(R.string.keyboard_key_numpad_template, "="));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, "("));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, ")"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_ZENKAKU_HANKAKU, "半角/全角");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_EISU, "英数");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MUHENKAN, "無変換");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_HENKAN, "変換");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_KATAKANA_HIRAGANA, "かな");
+
+ mModifierNames.put(KeyEvent.META_META_ON, "Meta");
+ mModifierNames.put(KeyEvent.META_CTRL_ON, "Ctrl");
+ mModifierNames.put(KeyEvent.META_ALT_ON, "Alt");
+ mModifierNames.put(KeyEvent.META_SHIFT_ON, "Shift");
+ mModifierNames.put(KeyEvent.META_SYM_ON, "Sym");
+ mModifierNames.put(KeyEvent.META_FUNCTION_ON, "Fn");
+
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DEL, context.getDrawable(R.drawable.ic_ksh_key_backspace));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_ENTER, context.getDrawable(R.drawable.ic_ksh_key_enter));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_UP, context.getDrawable(R.drawable.ic_ksh_key_up));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_RIGHT, context.getDrawable(R.drawable.ic_ksh_key_right));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_DOWN, context.getDrawable(R.drawable.ic_ksh_key_down));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_LEFT, context.getDrawable(R.drawable.ic_ksh_key_left));
+
+ mModifierDrawables.put(
+ KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
+ }
+
+ private void createHardcodedShortcuts() {
+ // Add system shortcuts
+ mKeySearchResultMap.put(SHORTCUT_SYSTEM_INDEX, true);
+ mSystemGroup.add(getMultiMappingSystemShortcuts(mContext));
+ mSystemGroup.add(getSystemMultitaskingShortcuts(mContext));
+ // Add input shortcuts
+ mKeySearchResultMap.put(SHORTCUT_INPUT_INDEX, true);
+ mInputGroup.add(getMultiMappingInputShortcuts(mContext));
+ // Add open apps shortcuts
+ final List<KeyboardShortcutMultiMappingGroup> appShortcuts =
+ Arrays.asList(getDefaultMultiMappingApplicationShortcuts());
+ if (appShortcuts != null && !appShortcuts.isEmpty()) {
+ mOpenAppsGroup = appShortcuts;
+ mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, true);
+ } else {
+ mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, false);
+ }
+ }
+
+ /**
+ * Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
+ * existing device, that device's map is used. Otherwise, it checks first all available devices
+ * and if there is a full keyboard it uses that map, otherwise falls back to the Virtual
+ * Keyboard with its default map.
+ */
+ private void retrieveKeyCharacterMap(int deviceId) {
+ final InputManager inputManager = InputManager.getInstance();
+ mBackupKeyCharacterMap = inputManager.getInputDevice(-1).getKeyCharacterMap();
+ if (deviceId != -1) {
+ final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
+ if (inputDevice != null) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ final int[] deviceIds = inputManager.getInputDeviceIds();
+ for (int id : deviceIds) {
+ final InputDevice inputDevice = inputManager.getInputDevice(id);
+ // -1 is the Virtual Keyboard, with the default key map. Use that one only as last
+ // resort.
+ if (inputDevice.getId() != -1 && inputDevice.isFullKeyboard()) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ // Fall back to -1, the virtual keyboard.
+ mKeyCharacterMap = mBackupKeyCharacterMap;
+ }
+
+ @VisibleForTesting
+ void showKeyboardShortcuts(int deviceId) {
+ retrieveKeyCharacterMap(deviceId);
+ mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+ @Override
+ public void onKeyboardShortcutsReceived(
+ final List<KeyboardShortcutGroup> result) {
+ // Add specific app shortcuts
+ if (result.isEmpty()) {
+ mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, false);
+ } else {
+ mSpecificAppGroup = reMapToKeyboardShortcutMultiMappingGroup(result);
+ mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, true);
+ }
+ mFullShortsGroup.add(SHORTCUT_SYSTEM_INDEX, mSystemGroup);
+ mFullShortsGroup.add(SHORTCUT_INPUT_INDEX, mInputGroup);
+ mFullShortsGroup.add(SHORTCUT_OPENAPPS_INDEX, mOpenAppsGroup);
+ mFullShortsGroup.add(SHORTCUT_SPECIFICAPP_INDEX, mSpecificAppGroup);
+ showKeyboardShortcutSearchList(mFullShortsGroup);
+ }
+ }, deviceId);
+ }
+
+ // The original data structure is only for 1-to-1 shortcut mapping, so remap the old
+ // data structure to the new data structure for handling the N-to-1 key mapping and other
+ // complex case.
+ private List<KeyboardShortcutMultiMappingGroup> reMapToKeyboardShortcutMultiMappingGroup(
+ List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+ new ArrayList<>();
+ for (KeyboardShortcutGroup group : keyboardShortcutGroups) {
+ CharSequence categoryTitle = group.getLabel();
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+ for (KeyboardShortcutInfo info : group.getItems()) {
+ shortcutMultiMappingInfos.add(new ShortcutMultiMappingInfo(info));
+ }
+ keyboardShortcutMultiMappingGroups.add(
+ new KeyboardShortcutMultiMappingGroup(
+ categoryTitle, shortcutMultiMappingInfos));
+ }
+ return keyboardShortcutMultiMappingGroups;
+ }
+
+ private void dismissKeyboardShortcuts() {
+ if (mKeyboardShortcutsBottomSheetDialog != null) {
+ mKeyboardShortcutsBottomSheetDialog.dismiss();
+ mKeyboardShortcutsBottomSheetDialog = null;
+ }
+ }
+
+ private KeyboardShortcutMultiMappingGroup getMultiMappingSystemShortcuts(Context context) {
+ KeyboardShortcutMultiMappingGroup systemGroup =
+ new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_system),
+ new ArrayList<>());
+ List<ShortcutKeyGroupMultiMappingInfo> infoList = Arrays.asList(
+ /* Access notification shade: Meta + N */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_notification_shade),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_N, KeyEvent.META_META_ON))),
+ /* Take a full screenshot: Meta + Ctrl + S */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_full_screenshot),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_S,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))),
+ /* Access list of system / apps shortcuts: Meta + / */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_system_app_shortcuts),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON))),
+ /* Back: go back to previous state (back button) */
+ /* Meta + ~, Meta + backspace, Meta + left arrow */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_go_back),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_GRAVE, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
+ /* Access home screen: Meta + H, Meta + Enter */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_home_screen),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_H, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON))),
+ /* Overview of open apps: Meta + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_overview_open_apps),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
+ /* Cycle through recent apps (forward): Alt + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_cycle_forward),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON))),
+ /* Cycle through recent apps (back): Shift + Alt + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_cycle_back),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_TAB,
+ KeyEvent.META_SHIFT_ON | KeyEvent.META_ALT_ON))),
+ /* Access list of all apps and search (i.e. Search/Launcher): Meta */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_all_apps_search),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON))),
+ /* Hide and (re)show taskbar: Meta + T */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_hide_reshow_taskbar),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_T, KeyEvent.META_META_ON))),
+ /* Access system settings: Meta + I */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_system_settings),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_I, KeyEvent.META_META_ON))),
+ /* Access Google Assistant: Meta + A */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_google_assistant),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
+ /* Lock screen: Meta + L */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_lock_screen),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
+ /* Pull up Notes app for quick memo: Meta + Ctrl + N */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_quick_memo),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_N,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+ );
+ for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
+ systemGroup.addItem(info.getShortcutMultiMappingInfo());
+ }
+ return systemGroup;
+ }
+
+ private static class ShortcutKeyGroupMultiMappingInfo {
+ private String mLabel;
+ private List<Pair<Integer, Integer>> mKeycodeGroupList;
+
+ ShortcutKeyGroupMultiMappingInfo(
+ String label, List<Pair<Integer, Integer>> keycodeGroupList) {
+ mLabel = label;
+ mKeycodeGroupList = keycodeGroupList;
+ }
+
+ ShortcutMultiMappingInfo getShortcutMultiMappingInfo() {
+ List<ShortcutKeyGroup> shortcutKeyGroups = new ArrayList<>();
+ for (Pair<Integer, Integer> keycodeGroup : mKeycodeGroupList) {
+ shortcutKeyGroups.add(new ShortcutKeyGroup(
+ new KeyboardShortcutInfo(
+ mLabel,
+ keycodeGroup.first /* keycode */,
+ keycodeGroup.second /* modifiers*/),
+ null));
+ }
+ ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+ new ShortcutMultiMappingInfo(mLabel, null, shortcutKeyGroups);
+ return shortcutMultiMappingInfo;
+ }
+ }
+
+ private static KeyboardShortcutMultiMappingGroup getSystemMultitaskingShortcuts(
+ Context context) {
+ KeyboardShortcutMultiMappingGroup systemMultitaskingGroup =
+ new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_system_multitasking),
+ new ArrayList<>());
+
+ // System multitasking shortcuts:
+ // Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
+ // Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
+ // Switch from Split screen to full screen: Meta + Ctrl + Up arrow
+ // During Split screen: replace an app from one to another: Meta + Ctrl + Down arrow
+ String[] shortcutLabels = {
+ context.getString(R.string.system_multitasking_rhs),
+ context.getString(R.string.system_multitasking_lhs),
+ context.getString(R.string.system_multitasking_full_screen),
+ context.getString(R.string.system_multitasking_replace)
+ };
+ int[] keyCodes = {
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN
+ };
+
+ for (int i = 0; i < shortcutLabels.length; i++) {
+ List<ShortcutKeyGroup> shortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(
+ new KeyboardShortcutInfo(
+ shortcutLabels[i],
+ keyCodes[i],
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON),
+ null));
+ ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+ new ShortcutMultiMappingInfo(
+ shortcutLabels[i],
+ null,
+ shortcutKeyGroups);
+ systemMultitaskingGroup.addItem(shortcutMultiMappingInfo);
+ }
+ return systemMultitaskingGroup;
+ }
+
+ private static KeyboardShortcutMultiMappingGroup getMultiMappingInputShortcuts(
+ Context context) {
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfoList = Arrays.asList(
+ /* Switch input language (next language): Ctrl + Space or Meta + Space */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_switch_input_language_next),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_next),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_CTRL_ON),
+ null),
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_next),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON),
+ null))),
+ /* Switch input language (previous language): */
+ /* Ctrl + Shift + Space or Meta + Shift + Space */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_switch_input_language_previous),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_previous),
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON),
+ null),
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_previous),
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON),
+ null))),
+ /* Access emoji: Meta + . */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_access_emoji),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(R.string.input_access_emoji),
+ KeyEvent.KEYCODE_PERIOD,
+ KeyEvent.META_META_ON),
+ null))),
+ /* Access voice typing: Meta + V */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_access_voice_typing),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(R.string.input_access_voice_typing),
+ KeyEvent.KEYCODE_V, KeyEvent.META_META_ON),
+ null)))
+ );
+ return new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_input),
+ shortcutMultiMappingInfoList);
+ }
+
+ private KeyboardShortcutMultiMappingGroup getDefaultMultiMappingApplicationShortcuts() {
+ final int userId = mContext.getUserId();
+ PackageInfo assistPackageInfo = getAssistPackageInfo(mContext, mPackageManager, userId);
+ CharSequence categoryTitle =
+ mContext.getString(R.string.keyboard_shortcut_group_applications);
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+
+ String[] intentCategories = {
+ Intent.CATEGORY_APP_BROWSER,
+ Intent.CATEGORY_APP_CONTACTS,
+ Intent.CATEGORY_APP_EMAIL,
+ Intent.CATEGORY_APP_CALENDAR,
+ Intent.CATEGORY_APP_MAPS,
+ Intent.CATEGORY_APP_MUSIC,
+ Intent.CATEGORY_APP_MESSAGING,
+ Intent.CATEGORY_APP_CALCULATOR,
+
+ };
+ String[] shortcutLabels = {
+ mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calculator)
+ };
+ int[] keyCodes = {
+ KeyEvent.KEYCODE_B,
+ KeyEvent.KEYCODE_C,
+ KeyEvent.KEYCODE_E,
+ KeyEvent.KEYCODE_K,
+ KeyEvent.KEYCODE_M,
+ KeyEvent.KEYCODE_P,
+ KeyEvent.KEYCODE_S,
+ KeyEvent.KEYCODE_U,
+ };
+
+ // Assist.
+ if (assistPackageInfo != null) {
+ if (assistPackageInfo != null) {
+ final Icon assistIcon = Icon.createWithResource(
+ assistPackageInfo.applicationInfo.packageName,
+ assistPackageInfo.applicationInfo.icon);
+ CharSequence assistLabel =
+ mContext.getString(R.string.keyboard_shortcut_group_applications_assist);
+ KeyboardShortcutInfo assistShortcutInfo = new KeyboardShortcutInfo(
+ assistLabel,
+ assistIcon,
+ KeyEvent.KEYCODE_A,
+ KeyEvent.META_META_ON);
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(
+ assistLabel,
+ assistIcon,
+ Arrays.asList(new ShortcutKeyGroup(assistShortcutInfo, null))));
+ }
+ }
+
+ // Browser (Chrome as default): Meta + B
+ // Contacts: Meta + C
+ // Email (Gmail as default): Meta + E
+ // Gmail: Meta + G
+ // Calendar: Meta + K
+ // Maps: Meta + M
+ // Music: Meta + P
+ // SMS: Meta + S
+ // Calculator: Meta + U
+ for (int i = 0; i < shortcutLabels.length; i++) {
+ final Icon icon = getIconForIntentCategory(intentCategories[i], userId);
+ if (icon != null) {
+ CharSequence label =
+ shortcutLabels[i];
+ KeyboardShortcutInfo keyboardShortcutInfo = new KeyboardShortcutInfo(
+ label,
+ icon,
+ keyCodes[i],
+ KeyEvent.META_META_ON);
+ List<ShortcutKeyGroup> shortcutKeyGroups =
+ Arrays.asList(new ShortcutKeyGroup(keyboardShortcutInfo, null));
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(label, icon, shortcutKeyGroups));
+ }
+ }
+
+ Comparator<ShortcutMultiMappingInfo> applicationItemsComparator =
+ new Comparator<ShortcutMultiMappingInfo>() {
+ @Override
+ public int compare(
+ ShortcutMultiMappingInfo ksh1, ShortcutMultiMappingInfo ksh2) {
+ boolean ksh1ShouldBeLast = ksh1.getLabel() == null
+ || ksh1.getLabel().toString().isEmpty();
+ boolean ksh2ShouldBeLast = ksh2.getLabel() == null
+ || ksh2.getLabel().toString().isEmpty();
+ if (ksh1ShouldBeLast && ksh2ShouldBeLast) {
+ return 0;
+ }
+ if (ksh1ShouldBeLast) {
+ return 1;
+ }
+ if (ksh2ShouldBeLast) {
+ return -1;
+ }
+ return (ksh1.getLabel().toString()).compareToIgnoreCase(
+ ksh2.getLabel().toString());
+ }
+ };
+ // Sorts by label, case insensitive with nulls and/or empty labels last.
+ Collections.sort(shortcutMultiMappingInfos, applicationItemsComparator);
+ return new KeyboardShortcutMultiMappingGroup(categoryTitle, shortcutMultiMappingInfos);
+ }
+
+ private Icon getIconForIntentCategory(String intentCategory, int userId) {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(intentCategory);
+
+ final PackageInfo packageInfo = getPackageInfoForIntent(intent, userId);
+ if (packageInfo != null && packageInfo.applicationInfo.icon != 0) {
+ return Icon.createWithResource(
+ packageInfo.applicationInfo.packageName,
+ packageInfo.applicationInfo.icon);
+ }
+ return null;
+ }
+
+ private PackageInfo getPackageInfoForIntent(Intent intent, int userId) {
+ try {
+ ResolveInfo handler;
+ handler = mPackageManager.resolveIntent(
+ intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId);
+ if (handler == null || handler.activityInfo == null) {
+ return null;
+ }
+ return mPackageManager.getPackageInfo(handler.activityInfo.packageName, 0, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PackageManagerService is dead", e);
+ return null;
+ }
+ }
+
+ private void showKeyboardShortcutSearchList(
+ List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+ // Need to post on the main thread.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleShowKeyboardShortcutSearchList(keyboardShortcutMultiMappingGroupList);
+ }
+ });
+ }
+
+ private void handleShowKeyboardShortcutSearchList(
+ List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+ mQueryString = null;
+ LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+ mKeyboardShortcutsBottomSheetDialog =
+ new BottomSheetDialog(mContext);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_search_view, null);
+ mNoSearchResults = keyboardShortcutsView.findViewById(R.id.shortcut_search_no_result);
+ mKeyboardShortcutsBottomSheetDialog.setContentView(keyboardShortcutsView);
+ setButtonsDefaultStatus(keyboardShortcutsView);
+ populateKeyboardShortcutSearchList(
+ keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_container));
+
+ // Workaround for solve issue about dialog not full expanded when landscape.
+ FrameLayout bottomSheet = (FrameLayout)
+ mKeyboardShortcutsBottomSheetDialog.findViewById(
+ com.google.android.material.R.id.design_bottom_sheet);
+ if (bottomSheet != null) {
+ bottomSheet.setBackgroundResource(android.R.color.transparent);
+ }
+
+ BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
+ behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
+ behavior.setSkipCollapsed(true);
+
+ mKeyboardShortcutsBottomSheetDialog.setCanceledOnTouchOutside(true);
+ Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ synchronized (sLock) {
+ // show KeyboardShortcutsBottomSheetDialog only if it has not been dismissed already
+ if (sInstance != null) {
+ mKeyboardShortcutsBottomSheetDialog.show();
+ setDialogScreenSize();
+ keyboardShortcutsView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ setDialogScreenSize();
+ }
+ });
+ }
+ }
+ mSearchEditText = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search);
+ mSearchEditText.addTextChangedListener(
+ new TextWatcher() {
+ @Override
+ public void afterTextChanged(Editable s) {
+ mQueryString = s.toString();
+ populateKeyboardShortcutSearchList(
+ keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Do nothing.
+ }
+ });
+ mEditTextCancel = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search_cancel);
+ mEditTextCancel.setOnClickListener(v -> mSearchEditText.setText(null));
+ }
+
+ private void populateKeyboardShortcutSearchList(LinearLayout keyboardShortcutsLayout) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ TextView shortcutsKeyView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_view, keyboardShortcutsLayout, false);
+ shortcutsKeyView.measure(
+ View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ final int shortcutKeyTextItemMinWidth = shortcutsKeyView.getMeasuredHeight();
+ // Needed to be able to scale the image items to the same height as the text items.
+ final int shortcutKeyIconItemHeightWidth = shortcutsKeyView.getMeasuredHeight()
+ - shortcutsKeyView.getPaddingTop()
+ - shortcutsKeyView.getPaddingBottom();
+ keyboardShortcutsLayout.removeAllViews();
+
+ // Search if user's input is contained in any shortcut groups.
+ if (mQueryString != null) {
+ for (int i = 0; i < mFullShortsGroup.size(); i++) {
+ mKeySearchResultMap.put(i, false);
+ for (KeyboardShortcutMultiMappingGroup group : mFullShortsGroup.get(i)) {
+ for (ShortcutMultiMappingInfo info : group.getItems()) {
+ String itemLabel = info.getLabel().toString();
+ if (itemLabel.toUpperCase(Locale.getDefault()).contains(
+ mQueryString.toUpperCase(Locale.getDefault()))) {
+ mKeySearchResultMap.put(i, true);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Set default color for the non-focus categories.
+ for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+ if (mKeySearchResultMap.get(i)) {
+ mFullButtonList.get(i).setVisibility(View.VISIBLE);
+ setButtonFocusColor(i, false);
+ } else {
+ mFullButtonList.get(i).setVisibility(View.GONE);
+ }
+ }
+
+ // Move the focus to the suitable category.
+ if (mFullButtonList.get(mCurrentCategoryIndex).getVisibility() == View.GONE) {
+ for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+ if (mKeySearchResultMap.get(i)) {
+ setCurrentCategoryIndex(i);
+ break;
+ }
+ }
+ }
+
+ // Set color for the current focus category
+ setButtonFocusColor(mCurrentCategoryIndex, true);
+
+ // Load shortcuts for current focus category.
+ List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+ mFullShortsGroup.get(mCurrentCategoryIndex);
+
+ int keyboardShortcutGroupsSize = keyboardShortcutMultiMappingGroups.size();
+ List<Boolean> groupSearchResult = new ArrayList<>();
+ for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+ View separator = inflater.inflate(
+ R.layout.keyboard_shortcuts_category_short_separator,
+ keyboardShortcutsLayout,
+ false);
+
+ // If there are more than one category, add separators among categories.
+ if (i > 0) {
+ keyboardShortcutsLayout.addView(separator);
+ }
+
+ List<Boolean> itemSearchResult = new ArrayList<>();
+ KeyboardShortcutMultiMappingGroup categoryGroup =
+ keyboardShortcutMultiMappingGroups.get(i);
+ TextView categoryTitle = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+ categoryTitle.setText(categoryGroup.getCategory());
+ keyboardShortcutsLayout.addView(categoryTitle);
+ LinearLayout shortcutContainer = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_container, keyboardShortcutsLayout, false);
+ final int itemsSize = categoryGroup.getItems().size();
+ for (int j = 0; j < itemsSize; j++) {
+ ShortcutMultiMappingInfo keyGroupInfo = categoryGroup.getItems().get(j);
+
+ if (mQueryString != null) {
+ String shortcutLabel =
+ keyGroupInfo.getLabel().toString().toUpperCase(Locale.getDefault());
+ String queryString = mQueryString.toUpperCase(Locale.getDefault());
+ if (!shortcutLabel.contains(queryString)) {
+ itemSearchResult.add(j, false);
+ continue;
+ } else {
+ itemSearchResult.add(j, true);
+ }
+ }
+
+ View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
+ shortcutContainer, false);
+ TextView shortcutKeyword =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_keyword);
+ shortcutKeyword.setText(keyGroupInfo.getLabel());
+
+ if (keyGroupInfo.getIcon() != null) {
+ ImageView shortcutIcon =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_icon);
+ shortcutIcon.setImageIcon(keyGroupInfo.getIcon());
+ shortcutIcon.setVisibility(View.VISIBLE);
+ RelativeLayout.LayoutParams lp =
+ (RelativeLayout.LayoutParams) shortcutKeyword.getLayoutParams();
+ lp.removeRule(RelativeLayout.ALIGN_PARENT_START);
+ shortcutKeyword.setLayoutParams(lp);
+ }
+
+ ViewGroup shortcutItemsContainer =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_item_container);
+ final int keyGroupItemsSize = keyGroupInfo.getShortcutKeyGroups().size();
+ for (int p = 0; p < keyGroupItemsSize; p++) {
+ KeyboardShortcutInfo keyboardShortcutInfo =
+ keyGroupInfo.getShortcutKeyGroups().get(p).getKeyboardShortcutInfo();
+ String complexCommand =
+ keyGroupInfo.getShortcutKeyGroups().get(p).getComplexCommand();
+
+ if (complexCommand == null) {
+ List<StringDrawableContainer> shortcutKeys =
+ getHumanReadableShortcutKeys(keyboardShortcutInfo);
+ if (shortcutKeys == null) {
+ // Ignore shortcuts we can't display keys for.
+ Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
+ continue;
+ }
+ final int shortcutKeysSize = shortcutKeys.size();
+ for (int k = 0; k < shortcutKeysSize; k++) {
+ StringDrawableContainer shortcutRepresentation = shortcutKeys.get(k);
+ if (shortcutRepresentation.mDrawable != null) {
+ ImageView shortcutKeyIconView = (ImageView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_icon_view,
+ shortcutItemsContainer,
+ false);
+ Bitmap bitmap = Bitmap.createBitmap(shortcutKeyIconItemHeightWidth,
+ shortcutKeyIconItemHeightWidth, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ shortcutRepresentation.mDrawable.setBounds(0, 0, canvas.getWidth(),
+ canvas.getHeight());
+ shortcutRepresentation.mDrawable.draw(canvas);
+ shortcutKeyIconView.setImageBitmap(bitmap);
+ shortcutKeyIconView.setImportantForAccessibility(
+ IMPORTANT_FOR_ACCESSIBILITY_YES);
+ shortcutKeyIconView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
+ shortcutItemsContainer.addView(shortcutKeyIconView);
+ } else if (shortcutRepresentation.mString != null) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_view,
+ shortcutItemsContainer,
+ false);
+ shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+ shortcutKeyTextView.setText(shortcutRepresentation.mString);
+ shortcutKeyTextView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+
+ if (k < shortcutKeysSize - 1) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_plus_view,
+ shortcutItemsContainer,
+ false);
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+ }
+ } else {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_view,
+ shortcutItemsContainer,
+ false);
+ shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+ shortcutKeyTextView.setText(complexCommand);
+ shortcutKeyTextView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(complexCommand));
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+
+ if (p < keyGroupItemsSize - 1) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_vertical_bar_view,
+ shortcutItemsContainer,
+ false);
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+ }
+ shortcutContainer.addView(shortcutView);
+ }
+
+ if (!groupSearchResult.isEmpty() && !groupSearchResult.get(i - 1)) {
+ keyboardShortcutsLayout.removeView(separator);
+ }
+
+ if (!itemSearchResult.isEmpty() && !itemSearchResult.contains(true)) {
+ // No results, so remove the category title and separator
+ keyboardShortcutsLayout.removeView(categoryTitle);
+ keyboardShortcutsLayout.removeView(separator);
+ groupSearchResult.add(false);
+ if (i == keyboardShortcutGroupsSize - 1 && !groupSearchResult.contains(true)) {
+ // show "No shortcut found"
+ mNoSearchResults.setVisibility(View.VISIBLE);
+ }
+ continue;
+ }
+ groupSearchResult.add(true);
+ mNoSearchResults.setVisibility(View.GONE);
+ keyboardShortcutsLayout.addView(shortcutContainer);
+ }
+ }
+
+ private List<StringDrawableContainer> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+ List<StringDrawableContainer> shortcutKeys = getHumanReadableModifiers(info);
+ if (shortcutKeys == null) {
+ return null;
+ }
+ String shortcutKeyString = null;
+ Drawable shortcutKeyDrawable = null;
+ if (info.getBaseCharacter() > Character.MIN_VALUE) {
+ shortcutKeyString = String.valueOf(info.getBaseCharacter());
+ } else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
+ shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+ } else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+ } else {
+ // Special case for shortcuts with no base key or keycode.
+ if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ return shortcutKeys;
+ }
+ char displayLabel = mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ if (displayLabel != 0) {
+ shortcutKeyString = String.valueOf(displayLabel);
+ } else {
+ displayLabel = mBackupKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ if (displayLabel != 0) {
+ shortcutKeyString = String.valueOf(displayLabel);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ if (shortcutKeyString != null) {
+ shortcutKeys.add(new StringDrawableContainer(shortcutKeyString, shortcutKeyDrawable));
+ } else {
+ Log.w(TAG, "Keyboard Shortcut does not have a text representation, skipping.");
+ }
+
+ return shortcutKeys;
+ }
+
+ private List<StringDrawableContainer> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+ final List<StringDrawableContainer> shortcutKeys = new ArrayList<>();
+ int modifiers = info.getModifiers();
+ if (modifiers == 0) {
+ return shortcutKeys;
+ }
+ for (int supportedModifier : mModifierList) {
+ if ((modifiers & supportedModifier) != 0) {
+ shortcutKeys.add(new StringDrawableContainer(
+ mModifierNames.get(supportedModifier),
+ mModifierDrawables.get(supportedModifier)));
+ modifiers &= ~supportedModifier;
+ }
+ }
+ if (modifiers != 0) {
+ // Remaining unsupported modifiers, don't show anything.
+ return null;
+ }
+ return shortcutKeys;
+ }
+
+ private final class ShortcutKeyAccessibilityDelegate extends AccessibilityDelegate {
+ private String mContentDescription;
+
+ ShortcutKeyAccessibilityDelegate(String contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (mContentDescription != null) {
+ info.setContentDescription(mContentDescription.toLowerCase(Locale.getDefault()));
+ }
+ }
+ }
+
+ private static final class StringDrawableContainer {
+ @NonNull
+ public String mString;
+ @Nullable
+ public Drawable mDrawable;
+
+ StringDrawableContainer(String string, Drawable drawable) {
+ mString = string;
+ mDrawable = drawable;
+ }
+ }
+
+ private void setDialogScreenSize() {
+ Window window = mKeyboardShortcutsBottomSheetDialog.getWindow();
+ Display display = mWindowManager.getDefaultDisplay();
+ WindowManager.LayoutParams lp =
+ mKeyboardShortcutsBottomSheetDialog.getWindow().getAttributes();
+ if (mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT) {
+ lp.width = (int) (display.getWidth() * 0.8);
+ lp.height = (int) (display.getHeight() * 0.7);
+ } else {
+ lp.width = (int) (display.getWidth() * 0.7);
+ lp.height = (int) (display.getHeight() * 0.8);
+ }
+ window.setGravity(Gravity.BOTTOM);
+ window.setAttributes(lp);
+ }
+
+ private void setCurrentCategoryIndex(int index) {
+ mCurrentCategoryIndex = index;
+ }
+
+ private void setButtonsDefaultStatus(View keyboardShortcutsView) {
+ mButtonSystem = keyboardShortcutsView.findViewById(R.id.shortcut_system);
+ mButtonInput = keyboardShortcutsView.findViewById(R.id.shortcut_input);
+ mButtonOpenApps = keyboardShortcutsView.findViewById(R.id.shortcut_open_apps);
+ mButtonSpecificApp = keyboardShortcutsView.findViewById(R.id.shortcut_specific_app);
+
+ mButtonSystem.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_SYSTEM_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonInput.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_INPUT_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonOpenApps.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_OPENAPPS_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonSpecificApp.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_SPECIFICAPP_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mFullButtonList.add(mButtonSystem);
+ mFullButtonList.add(mButtonInput);
+ mFullButtonList.add(mButtonOpenApps);
+ mFullButtonList.add(mButtonSpecificApp);
+ }
+
+ private void setButtonFocusColor(int i, boolean isFocused) {
+ if (isFocused) {
+ mFullButtonList.get(i).setTextColor(getColorOfTextColorOnAccent());
+ mFullButtonList.get(i).setBackground(
+ mContext.getDrawable(R.drawable.shortcut_button_focus_colored));
+ } else {
+ // Default color
+ mFullButtonList.get(i).setTextColor(getColorOfTextColorSecondary());
+ mFullButtonList.get(i).setBackground(
+ mContext.getDrawable(R.drawable.shortcut_button_colored));
+ }
+ }
+
+ private int getColorOfTextColorOnAccent() {
+ return Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorOnAccent);
+ }
+
+ private int getColorOfTextColorSecondary() {
+ return Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorSecondary);
+ }
+
+ // Create the new data structure for handling the N-to-1 key mapping and other complex case.
+ private static class KeyboardShortcutMultiMappingGroup {
+ private final CharSequence mCategory;
+ private List<ShortcutMultiMappingInfo> mItems;
+
+ KeyboardShortcutMultiMappingGroup(
+ CharSequence category, List<ShortcutMultiMappingInfo> items) {
+ mCategory = category;
+ mItems = items;
+ }
+
+ void addItem(ShortcutMultiMappingInfo item) {
+ mItems.add(item);
+ }
+
+ CharSequence getCategory() {
+ return mCategory;
+ }
+
+ List<ShortcutMultiMappingInfo> getItems() {
+ return mItems;
+ }
+ }
+
+ private static class ShortcutMultiMappingInfo {
+ private final CharSequence mLabel;
+ private final Icon mIcon;
+ private List<ShortcutKeyGroup> mShortcutKeyGroups;
+
+ ShortcutMultiMappingInfo(
+ CharSequence label, Icon icon, List<ShortcutKeyGroup> shortcutKeyGroups) {
+ mLabel = label;
+ mIcon = icon;
+ mShortcutKeyGroups = shortcutKeyGroups;
+ }
+
+ ShortcutMultiMappingInfo(KeyboardShortcutInfo info) {
+ mLabel = info.getLabel();
+ mIcon = info.getIcon();
+ mShortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(info, null));
+ }
+
+ CharSequence getLabel() {
+ return mLabel;
+ }
+
+ Icon getIcon() {
+ return mIcon;
+ }
+
+ List<ShortcutKeyGroup> getShortcutKeyGroups() {
+ return mShortcutKeyGroups;
+ }
+ }
+
+ private static class ShortcutKeyGroup {
+ private final KeyboardShortcutInfo mKeyboardShortcutInfo;
+ private final String mComplexCommand;
+
+ ShortcutKeyGroup(KeyboardShortcutInfo keyboardShortcutInfo, String complexCommand) {
+ mKeyboardShortcutInfo = keyboardShortcutInfo;
+ mComplexCommand = complexCommand;
+ }
+
+ // To be compatible with the original functions, keep KeyboardShortcutInfo in here.
+ KeyboardShortcutInfo getKeyboardShortcutInfo() {
+ return mKeyboardShortcutInfo;
+ }
+
+ // In some case, the shortcut is a complex description not a N-to-1 key mapping.
+ String getComplexCommand() {
+ return mComplexCommand;
+ }
+ }
+
+ private static PackageInfo getAssistPackageInfo(
+ Context context, IPackageManager packageManager, int userId) {
+ AssistUtils assistUtils = new AssistUtils(context);
+ ComponentName assistComponent = assistUtils.getAssistComponentForUser(userId);
+ // Not all devices have an assist component.
+ PackageInfo assistPackageInfo = null;
+ if (assistComponent != null) {
+ try {
+ assistPackageInfo = packageManager.getPackageInfo(
+ assistComponent.getPackageName(), 0, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PackageManagerService is dead");
+ }
+ }
+ return assistPackageInfo;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 7e6ddcf..f20f929 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -63,6 +63,7 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -80,7 +81,8 @@
public final class KeyboardShortcuts {
private static final String TAG = KeyboardShortcuts.class.getSimpleName();
private static final Object sLock = new Object();
- private static KeyboardShortcuts sInstance;
+ @VisibleForTesting static KeyboardShortcuts sInstance;
+ private WindowManager mWindowManager;
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
@@ -94,7 +96,7 @@
};
private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final Context mContext;
+ @VisibleForTesting Context mContext;
private final IPackageManager mPackageManager;
private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
@@ -123,20 +125,26 @@
}
};
- private Dialog mKeyboardShortcutsDialog;
+ @VisibleForTesting Dialog mKeyboardShortcutsDialog;
private KeyCharacterMap mKeyCharacterMap;
private KeyCharacterMap mBackupKeyCharacterMap;
- private KeyboardShortcuts(Context context) {
+ @VisibleForTesting
+ KeyboardShortcuts(Context context, WindowManager windowManager) {
this.mContext = new ContextThemeWrapper(
context, android.R.style.Theme_DeviceDefault_Settings);
this.mPackageManager = AppGlobals.getPackageManager();
+ if (windowManager != null) {
+ this.mWindowManager = windowManager;
+ } else {
+ this.mWindowManager = mContext.getSystemService(WindowManager.class);
+ }
loadResources(context);
}
private static KeyboardShortcuts getInstance(Context context) {
if (sInstance == null) {
- sInstance = new KeyboardShortcuts(context);
+ sInstance = new KeyboardShortcuts(context, null);
}
return sInstance;
}
@@ -371,10 +379,10 @@
mKeyCharacterMap = mBackupKeyCharacterMap;
}
- private void showKeyboardShortcuts(int deviceId) {
+ @VisibleForTesting
+ void showKeyboardShortcuts(int deviceId) {
retrieveKeyCharacterMap(deviceId);
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+ mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
@Override
public void onKeyboardShortcutsReceived(
final List<KeyboardShortcutGroup> result) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 8a5bece..e9fac28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -19,16 +19,38 @@
import android.content.Context;
import android.content.Intent;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import javax.inject.Inject;
+
/**
* Receiver for the Keyboard Shortcuts Helper.
*/
public class KeyboardShortcutsReceiver extends BroadcastReceiver {
+
+ private boolean mIsShortcutListSearchEnabled;
+
+ @Inject
+ public KeyboardShortcutsReceiver(FeatureFlags featureFlags) {
+ mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
- } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(context)) {
+ if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcutListSearch.show(context, -1 /* deviceId unknown */);
+ } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcutListSearch.dismiss();
+ }
+ } else {
+ if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
+ } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcuts.dismiss();
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 250900e..d3927a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -185,6 +185,7 @@
private boolean mPowerCharged;
private boolean mBatteryOverheated;
private boolean mEnableBatteryDefender;
+ private boolean mIncompatibleCharger;
private int mChargingSpeed;
private int mChargingWattage;
private int mBatteryLevel;
@@ -903,6 +904,10 @@
chargingId = R.string.keyguard_plugged_in_charging_limited;
String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
return mContext.getResources().getString(chargingId, percentage);
+ } else if (mPowerPluggedIn && mIncompatibleCharger) {
+ chargingId = R.string.keyguard_plugged_in_incompatible_charger;
+ String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
+ return mContext.getResources().getString(chargingId, percentage);
} else if (mPowerCharged) {
return mContext.getResources().getString(R.string.keyguard_charged);
}
@@ -1063,6 +1068,7 @@
mBatteryPresent = status.present;
mBatteryOverheated = status.isOverheated();
mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn();
+ mIncompatibleCharger = status.incompatibleCharger.orElse(false);
try {
mChargingTimeRemaining = mPowerPluggedIn
? mBatteryInfo.computeChargeTimeRemaining() : -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 1966a66..6a52a33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -186,11 +186,13 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcutListSearch;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LiftReveal;
@@ -299,6 +301,7 @@
private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
private float mTransitionToFullShadeProgress = 0f;
private NotificationListContainer mNotifListContainer;
+ private boolean mIsShortcutListSearchEnabled;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
@@ -833,6 +836,7 @@
mCameraLauncherLazy = cameraLauncherLazy;
mAlternateBouncerInteractor = alternateBouncerInteractor;
mUserTracker = userTracker;
+ mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -2546,7 +2550,11 @@
String action = intent.getAction();
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.dismiss();
+ } else {
+ KeyboardShortcuts.dismiss();
+ }
mRemoteInputManager.closeRemoteInputs();
if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
@@ -3893,11 +3901,19 @@
}
protected void toggleKeyboardShortcuts(int deviceId) {
- KeyboardShortcuts.toggle(mContext, deviceId);
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.toggle(mContext, deviceId);
+ } else {
+ KeyboardShortcuts.toggle(mContext, deviceId);
+ }
}
protected void dismissKeyboardShortcuts() {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.dismiss();
+ } else {
+ KeyboardShortcuts.dismiss();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 3f54aebf..dee4a6f 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -30,6 +30,9 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.shared.hardware.hasInputDevice
+import com.android.systemui.shared.hardware.isInternalStylusSource
+import com.android.systemui.statusbar.notification.collection.listbuilder.DEBUG
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -59,8 +62,10 @@
CopyOnWriteArrayList()
// This map should only be accessed on the handler
private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap()
- // This variable should only be accessed on the handler
+
+ // These variables should only be accessed on the handler
private var hasStarted: Boolean = false
+ private var isInUsiSession: Boolean = false
/**
* Starts listening to InputManager InputDevice events. Will also load the InputManager snapshot
@@ -70,6 +75,10 @@
handler.post {
if (hasStarted) return@post
hasStarted = true
+ isInUsiSession =
+ inputManager.hasInputDevice {
+ it.isInternalStylusSource && isBatteryStateValid(it.batteryState)
+ }
addExistingStylusToMap()
inputManager.registerInputDeviceListener(this, handler)
@@ -177,7 +186,18 @@
handler.post {
if (!hasStarted) return@post
- if (batteryState.isPresent) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onBatteryStateChanged for $deviceId. " +
+ "batteryState present: ${batteryState.isPresent}, " +
+ "capacity: ${batteryState.capacity}"
+ )
+ }
+
+ val batteryStateValid = isBatteryStateValid(batteryState)
+ trackAndLogUsiSession(deviceId, batteryStateValid)
+ if (batteryStateValid) {
onStylusUsed()
}
@@ -221,6 +241,37 @@
executeStylusCallbacks { cb -> cb.onStylusFirstUsed() }
}
+ /**
+ * Uses the input device battery state to track whether a current USI session is active. The
+ * InputDevice battery state updates USI battery on USI stylus input, and removes the last-known
+ * USI stylus battery presence after 1 hour of not detecting input. As SysUI and StylusManager
+ * is persistently running, relies on tracking sessions via an in-memory isInUsiSession boolean.
+ */
+ private fun trackAndLogUsiSession(deviceId: Int, batteryStateValid: Boolean) {
+ // TODO(b/268618918) handle cases where an invalid battery callback from a previous stylus
+ // is sent after the actual valid callback
+ if (batteryStateValid && !isInUsiSession) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "USI battery newly present, entering new USI session. Device ID: $deviceId"
+ )
+ }
+ isInUsiSession = true
+ uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
+ } else if (!batteryStateValid && isInUsiSession) {
+ if (DEBUG) {
+ Log.d(TAG, "USI battery newly absent, exiting USI session Device ID: $deviceId")
+ }
+ isInUsiSession = false
+ uiEventLogger.log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+ }
+ }
+
+ private fun isBatteryStateValid(batteryState: BatteryState): Boolean {
+ return batteryState.isPresent && batteryState.capacity > 0.0f
+ }
+
private fun executeStylusCallbacks(run: (cb: StylusCallback) -> Unit) {
stylusCallbacks.forEach(run)
}
@@ -295,5 +346,6 @@
companion object {
private val TAG = StylusManager::class.simpleName.orEmpty()
+ private val DEBUG = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
index 99da4ce..e77749b 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUiEvent.kt
@@ -31,7 +31,11 @@
@UiEvent(doc = "UIEvent for Toast shown when stylus stopped charging")
STYLUS_STOPPED_CHARGING(1303),
@UiEvent(doc = "UIEvent for bluetooth stylus connected") BLUETOOTH_STYLUS_CONNECTED(1304),
- @UiEvent(doc = "UIEvent for bluetooth stylus disconnected") BLUETOOTH_STYLUS_DISCONNECTED(1305);
+ @UiEvent(doc = "UIEvent for bluetooth stylus disconnected") BLUETOOTH_STYLUS_DISCONNECTED(1305),
+ @UiEvent(doc = "UIEvent for start of a USI session via battery presence")
+ USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED(1306),
+ @UiEvent(doc = "UIEvent for end of a USI session via battery absence")
+ USI_STYLUS_BATTERY_PRESENCE_REMOVED(1307);
override fun getId() = _id
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 4110b5a..841ec4b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -85,8 +85,12 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
import android.net.Uri;
import android.nfc.NfcAdapter;
+import android.os.BatteryManager;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -117,6 +121,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
+import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
@@ -238,9 +243,16 @@
private UiEventLogger mUiEventLogger;
@Mock
private GlobalSettings mGlobalSettings;
- private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
@Mock
private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
+ @Mock
+ private UsbPort mUsbPort;
+ @Mock
+ private UsbManager mUsbManager;
+ @Mock
+ private UsbPortStatus mUsbPortStatus;
+ @Mock
+ private Uri mURI;
private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
private final int mCurrentUserId = 100;
@@ -252,9 +264,6 @@
@Captor
private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;
- @Mock
- private Uri mURI;
-
// Direct executor
private final Executor mBackgroundExecutor = Runnable::run;
private final Executor mMainExecutor = Runnable::run;
@@ -264,6 +273,7 @@
private MockitoSession mMockitoSession;
private StatusBarStateController.StateListener mStatusBarStateListener;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
+ private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
@Before
@@ -2373,6 +2383,55 @@
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
}
+ @Test
+ public void testBatteryChangedIntent_refreshBatteryInfo() {
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, getBatteryIntent());
+
+ BatteryStatus status = verifyRefreshBatteryInfo();
+ assertThat(status.incompatibleCharger.get()).isFalse();
+ assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+ }
+
+ @Test
+ public void testUsbComplianceIntent_refreshBatteryInfo() {
+ Context contextSpy = getSpyContext();
+ when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
+ .thenReturn(getBatteryIntent());
+
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
+ contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
+
+ mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+ }
+
+ @Test
+ public void testUsbComplianceIntent_refreshBatteryInfoWithIncompatibleCharger() {
+ Context contextSpy = getSpyContext();
+ setupIncompatibleCharging();
+ when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
+ .thenReturn(getBatteryIntent());
+
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
+ contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
+
+ mTestableLooper.processAllMessages();
+ assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isTrue();
+ }
+
+ @Test
+ public void testBatteryChangedIntent_unplugDevice_resetIncompatibleCharger() {
+ mKeyguardUpdateMonitor.mIncompatibleCharger = true;
+ Intent batteryChangedIntent =
+ getBatteryIntent().putExtra(BatteryManager.EXTRA_PLUGGED, -1);
+
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, batteryChangedIntent);
+
+ BatteryStatus status = verifyRefreshBatteryInfo();
+ assertThat(status.incompatibleCharger.get()).isFalse();
+ assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
+ }
+
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
@@ -2592,6 +2651,37 @@
return intent;
}
+ private BatteryStatus verifyRefreshBatteryInfo() {
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<BatteryStatus> captor = ArgumentCaptor.forClass(BatteryStatus.class);
+ verify(mTestCallback, atLeastOnce()).onRefreshBatteryInfo(captor.capture());
+ List<BatteryStatus> batteryStatusList = captor.getAllValues();
+ return batteryStatusList.get(batteryStatusList.size() - 1);
+ }
+
+ private void setupIncompatibleCharging() {
+ final List<UsbPort> usbPorts = new ArrayList<>();
+ usbPorts.add(mUsbPort);
+ when(mUsbManager.getPorts()).thenReturn(usbPorts);
+ when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
+ when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
+ when(mUsbPortStatus.isConnected()).thenReturn(true);
+ when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{1});
+ }
+
+ private Context getSpyContext() {
+ Context contextSpy = spy(mContext);
+ when(contextSpy.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
+ when(contextSpy.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
+ .thenReturn(new Intent(Intent.ACTION_BATTERY_CHANGED));
+ return contextSpy;
+ }
+
+ private Intent getBatteryIntent() {
+ return new Intent(Intent.ACTION_BATTERY_CHANGED).putExtra(
+ BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ }
+
private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
new file mode 100644
index 0000000..777dd4e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 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.accessibility.fontscaling
+
+import android.os.Handler
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.ImageView
+import android.widget.SeekBar
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.SystemSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [FontScalingDialog]. */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class FontScalingDialogTest : SysuiTestCase() {
+ private lateinit var fontScalingDialog: FontScalingDialog
+ private lateinit var systemSettings: SystemSettings
+ private val fontSizeValueArray: Array<String> =
+ mContext
+ .getResources()
+ .getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+
+ @Before
+ fun setUp() {
+ val mainHandler = Handler(TestableLooper.get(this).getLooper())
+ systemSettings = FakeSettings()
+ fontScalingDialog = FontScalingDialog(mContext, systemSettings as FakeSettings)
+ }
+
+ @Test
+ fun showTheDialog_seekbarIsShowingCorrectProgress() {
+ fontScalingDialog.show()
+
+ val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!!
+ val progress: Int = seekBar.getProgress()
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+
+ assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+
+ @Test
+ fun progressIsZero_clickIconEnd_seekBarProgressIncreaseOne_fontSizeScaled() {
+ fontScalingDialog.show()
+
+ val iconEnd: ImageView = fontScalingDialog.findViewById(R.id.icon_end)!!
+ val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+ fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+ val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+ seekBarWithIconButtonsView.setProgress(0)
+
+ iconEnd.performClick()
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+ assertThat(seekBar.getProgress()).isEqualTo(1)
+ assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+
+ @Test
+ fun progressIsMax_clickIconStart_seekBarProgressDecreaseOne_fontSizeScaled() {
+ fontScalingDialog.show()
+
+ val iconStart: ImageView = fontScalingDialog.findViewById(R.id.icon_start)!!
+ val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+ fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+ val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+ seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1)
+
+ iconStart.performClick()
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+ assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
+ assertThat(currentScale)
+ .isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
new file mode 100644
index 0000000..57abae0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.qs.tiles.dialog
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class FontScalingTileTest : SysuiTestCase() {
+ @Mock private lateinit var qsHost: QSTileHost
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var qsLogger: QSLogger
+ @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fontScalingTile: FontScalingTile
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ `when`(qsHost.getContext()).thenReturn(mContext)
+ fontScalingTile =
+ FontScalingTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ FalsingManagerFake(),
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ dialogLaunchAnimator,
+ FakeSettings()
+ )
+ fontScalingTile.initialize()
+ }
+
+ @Test
+ fun isNotAvailable_whenNotSupportedDevice_returnsFalse() {
+ val isAvailable = fontScalingTile.isAvailable()
+
+ assertThat(isAvailable).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
new file mode 100644
index 0000000..109f185
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutListSearchTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private static int DEVICE_ID = 1;
+ private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+ @Mock private BottomSheetDialog mBottomSheetDialog;
+ @Mock WindowManager mWindowManager;
+
+ @Before
+ public void setUp() {
+ mKeyboardShortcutListSearch = new KeyboardShortcutListSearch(mContext, mWindowManager);
+ mKeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+ mKeyboardShortcutListSearch.mKeyboardShortcutsBottomSheetDialog = mBottomSheetDialog;
+ mKeyboardShortcutListSearch.mContext = mContext;
+ }
+
+ @Test
+ public void toggle_isShowingTrue_instanceShouldBeNull() {
+ when(mBottomSheetDialog.isShowing()).thenReturn(true);
+
+ mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+ assertThat(mKeyboardShortcutListSearch.sInstance).isNull();
+ }
+
+ @Test
+ public void toggle_isShowingFalse_showKeyboardShortcuts() {
+ when(mBottomSheetDialog.isShowing()).thenReturn(false);
+
+ mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+ verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
new file mode 100644
index 0000000..bea2cfb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsReceiverTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private KeyboardShortcutsReceiver mKeyboardShortcutsReceiver;
+ private Intent mIntent;
+ private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+
+ @Mock private KeyboardShortcuts mKeyboardShortcuts;
+ @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+ @Before
+ public void setUp() {
+ mIntent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
+ mKeyboardShortcuts.mContext = mContext;
+ mKeyboardShortcutListSearch.mContext = mContext;
+ KeyboardShortcuts.sInstance = mKeyboardShortcuts;
+ KeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+ }
+
+ @Test
+ public void onReceive_whenFlagOffDeviceIsTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(true);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOffDeviceIsNotTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(false);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOnDeviceIsTablet_showKeyboardShortcutListSearch() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(true);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts, never()).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOnDeviceIsNotTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(false);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
new file mode 100644
index 0000000..ea822aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Dialog;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private static int DEVICE_ID = 1;
+ private KeyboardShortcuts mKeyboardShortcuts;
+
+ @Mock private Dialog mDialog;
+ @Mock WindowManager mWindowManager;
+
+ @Before
+ public void setUp() {
+ mKeyboardShortcuts = new KeyboardShortcuts(mContext, mWindowManager);
+ mKeyboardShortcuts.sInstance = mKeyboardShortcuts;
+ mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog;
+ mKeyboardShortcuts.mContext = mContext;
+ }
+
+ @Test
+ public void toggle_isShowingTrue_instanceShouldBeNull() {
+ when(mDialog.isShowing()).thenReturn(true);
+
+ mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+ assertThat(mKeyboardShortcuts.sInstance).isNull();
+ }
+
+ @Test
+ public void toggle_isShowingFalse_showKeyboardShortcuts() {
+ when(mDialog.isShowing()).thenReturn(false);
+
+ mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+ verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 0605398..8b0d4ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -327,6 +327,8 @@
// CentralSurfacesImpl's runtime flag check fails if the flag is absent.
// This value is unused, because test manifest is opted in.
mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
+ // Set default value to avoid IllegalStateException.
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
index 56203d9..6d7941f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -96,6 +96,9 @@
whenever(stylusDevice.bluetoothAddress).thenReturn(null)
whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ whenever(stylusDevice.batteryState).thenReturn(batteryState)
+ whenever(batteryState.capacity).thenReturn(0.5f)
+
whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice)
whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice)
whenever(inputManager.getInputDevice(BT_STYLUS_DEVICE_ID)).thenReturn(btStylusDevice)
@@ -494,6 +497,47 @@
}
@Test
+ fun onBatteryStateChanged_batteryPresent_notInUsiSession_logsSessionStart() {
+ whenever(batteryState.isPresent).thenReturn(true)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(uiEventLogger, times(1))
+ .log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED)
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryPresent_inUsiSession_doesNotLogSessionStart() {
+ whenever(batteryState.isPresent).thenReturn(true)
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+ clearInvocations(uiEventLogger)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(uiEventLogger, never()).log(any())
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryAbsent_notInUsiSession_doesNotLogSessionEnd() {
+ whenever(batteryState.isPresent).thenReturn(false)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(uiEventLogger, never()).log(any())
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryAbsent_inUsiSession_logSessionEnd() {
+ whenever(batteryState.isPresent).thenReturn(true)
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+ whenever(batteryState.isPresent).thenReturn(false)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(uiEventLogger, times(1)).log(StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED)
+ }
+
+ @Test
fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() {
whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(true)
whenever(batteryState.isPresent).thenReturn(true)
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 12a8230..4702734 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -396,5 +396,11 @@
// Note: this is a base ID, multiple notifications will be posted for each
// abusive apps, with notification ID based off this ID.
NOTE_ABUSIVE_BG_APPS_BASE = 0xc1b2508; // 203105544
+
+ // Notify the user that dialer and sms functionality are unavailable whilst the apps are
+ // paused in the work profile.
+ // Package: android
+ NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF = 1006;
+
}
}
diff --git a/services/api/current.txt b/services/api/current.txt
index a4deed3..5c7b947 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -85,69 +85,72 @@
method @Nullable public String getAppComponentFactory();
method @Nullable public String getApplicationClassName();
method @Nullable public String getBackupAgentName();
- method @DrawableRes public int getBannerRes();
+ method @DrawableRes public int getBannerResourceId();
method public int getBaseRevisionCode();
method public int getCategory();
method @Nullable public String getClassLoaderName();
method @Dimension(unit=android.annotation.Dimension.DP) public int getCompatibleWidthLimitDp();
- method @XmlRes public int getDataExtractionRulesRes();
- method @StringRes public int getDescriptionRes();
- method @XmlRes public int getFullBackupContentRes();
+ method @XmlRes public int getDataExtractionRulesResourceId();
+ method @StringRes public int getDescriptionResourceId();
+ method @XmlRes public int getFullBackupContentResourceId();
method public int getGwpAsanMode();
- method @DrawableRes public int getIconRes();
- method @StringRes public int getLabelRes();
+ method @DrawableRes public int getIconResourceId();
+ method @StringRes public int getLabelResourceId();
method @Dimension(unit=android.annotation.Dimension.DP) public int getLargestWidthLimitDp();
method @NonNull public java.util.List<java.lang.String> getLibraryNames();
- method @XmlRes public int getLocaleConfigRes();
- method @DrawableRes public int getLogoRes();
+ method @XmlRes public int getLocaleConfigResourceId();
+ method @DrawableRes public int getLogoResourceId();
method public long getLongVersionCode();
method public float getMaxAspectRatio();
method public float getMinAspectRatio();
method public int getNativeHeapZeroInitialized();
- method @XmlRes public int getNetworkSecurityConfigRes();
+ method @XmlRes public int getNetworkSecurityConfigResourceId();
method @Nullable public String getRequiredAccountType();
method @Dimension(unit=android.annotation.Dimension.DP) public int getRequiresSmallestWidthDp();
method @Nullable public String getRestrictedAccountType();
- method @DrawableRes public int getRoundIconRes();
+ method @DrawableRes public int getRoundIconResourceId();
method @Nullable public String getSdkLibraryName();
method @Nullable public String getSharedUserId();
- method @StringRes public int getSharedUserLabelRes();
+ method @StringRes public int getSharedUserLabelResourceId();
method @NonNull public java.util.List<com.android.server.pm.pkg.AndroidPackageSplit> getSplits();
method @Nullable public String getStaticSharedLibraryName();
method @NonNull public java.util.UUID getStorageUuid();
method public int getTargetSdkVersion();
- method @StyleRes public int getThemeRes();
+ method @StyleRes public int getThemeResourceId();
method public int getUiOptions();
method @Nullable public String getVersionName();
method @Nullable public String getZygotePreloadName();
+ method public boolean is32BitAbiPreferred();
method public boolean isAllowAudioPlaybackCapture();
- method public boolean isAllowBackup();
- method public boolean isAllowClearUserData();
- method public boolean isAllowClearUserDataOnFailedRestore();
method public boolean isAllowNativeHeapPointerTagging();
- method public boolean isAllowTaskReparenting();
method public boolean isAnyDensity();
method public boolean isAttributionsUserVisible();
+ method public boolean isBackupAllowed();
method public boolean isBackupInForeground();
- method public boolean isCantSaveState();
+ method public boolean isClearUserDataAllowed();
+ method public boolean isClearUserDataOnFailedRestoreAllowed();
+ method public boolean isCleartextTrafficAllowed();
method public boolean isCoreApp();
method public boolean isCrossProfile();
method public boolean isDebuggable();
+ method public boolean isDeclaredHavingCode();
method public boolean isDefaultToDeviceProtectedStorage();
method public boolean isDirectBootAware();
- method public boolean isExtractNativeLibs();
+ method public boolean isExtraLargeScreensSupported();
+ method public boolean isExtractNativeLibrariesRequested();
method public boolean isFactoryTest();
method public boolean isForceQueryable();
method public boolean isFullBackupOnly();
method public boolean isHardwareAccelerated();
- method public boolean isHasCode();
- method public boolean isHasFragileUserData();
method public boolean isIsolatedSplitLoading();
- method public boolean isKillAfterRestore();
+ method public boolean isKillAfterRestoreAllowed();
method public boolean isLargeHeap();
+ method public boolean isLargeScreensSupported();
method public boolean isLeavingSharedUser();
method public boolean isMultiArch();
method public boolean isNativeLibraryRootRequiresIsa();
+ method public boolean isNonSdkApiRequested();
+ method public boolean isNormalScreensSupported();
method public boolean isOnBackInvokedCallbackEnabled();
method public boolean isPersistent();
method public boolean isProfileable();
@@ -157,17 +160,14 @@
method public boolean isResetEnabledSettingsOnAppDataCleared();
method public boolean isResourceOverlay();
method public boolean isRestoreAnyVersion();
+ method public boolean isRtlSupported();
+ method public boolean isSaveStateDisallowed();
method public boolean isSignedWithPlatformKey();
- method public boolean isSupportsExtraLargeScreens();
- method public boolean isSupportsLargeScreens();
- method public boolean isSupportsNormalScreens();
- method public boolean isSupportsRtl();
- method public boolean isSupportsSmallScreens();
+ method public boolean isSmallScreensSupported();
+ method public boolean isTaskReparentingAllowed();
method public boolean isTestOnly();
- method public boolean isUse32BitAbi();
method public boolean isUseEmbeddedDex();
- method public boolean isUsesCleartextTraffic();
- method public boolean isUsesNonSdkApi();
+ method public boolean isUserDataFragile();
method public boolean isVmSafeMode();
}
@@ -299,11 +299,11 @@
public static final class ActivityInterceptorCallback.ActivityInterceptorInfo.Builder {
ctor public ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(int, int, int, int, int, @NonNull android.content.Intent, @NonNull android.content.pm.ResolveInfo, @NonNull android.content.pm.ActivityInfo);
method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo build();
- method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingFeatureId(@NonNull String);
- method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingPackage(@NonNull String);
- method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCheckedOptions(@NonNull android.app.ActivityOptions);
- method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setClearOptionsAnimationRunnable(@NonNull Runnable);
- method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setResolvedType(@NonNull String);
+ method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingFeatureId(@Nullable String);
+ method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCallingPackage(@Nullable String);
+ method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setCheckedOptions(@Nullable android.app.ActivityOptions);
+ method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setClearOptionsAnimationRunnable(@Nullable Runnable);
+ method @NonNull public com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo.Builder setResolvedType(@Nullable String);
}
public class ActivityInterceptorCallbackRegistry {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2aeaa2f..13f327c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -260,6 +260,10 @@
*/
private static final String KEY_LOW_SWAP_THRESHOLD_PERCENT = "low_swap_threshold_percent";
+ /** Default value for mFlagApplicationStartInfoEnabled. Defaults to false. */
+ private static final String KEY_DEFAULT_APPLICATION_START_INFO_ENABLED =
+ "enable_app_start_info";
+
/**
* Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
* Settings.Global. This allows it to be set experimentally unless it has been
@@ -550,6 +554,9 @@
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
+ // Indicates whether ApplicationStartInfo is enabled.
+ volatile boolean mFlagApplicationStartInfoEnabled;
+
// Indicates whether the background activity starts is enabled.
// Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED.
// If not set explicitly the default is controlled by DeviceConfig.
@@ -996,6 +1003,9 @@
case KEY_MAX_CACHED_PROCESSES:
updateMaxCachedProcesses();
break;
+ case KEY_DEFAULT_APPLICATION_START_INFO_ENABLED:
+ updateApplicationStartInfoEnabled();
+ break;
case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
updateBackgroundActivityStarts();
break;
@@ -1390,6 +1400,14 @@
Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
}
+ private void updateApplicationStartInfoEnabled() {
+ mFlagApplicationStartInfoEnabled =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_APPLICATION_START_INFO_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateBackgroundActivityStarts() {
mFlagBackgroundActivityStartsEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1970,6 +1988,10 @@
pw.println(mFgToBgFgsGraceDuration);
pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
pw.println(mFgsStartForegroundTimeoutMs);
+ pw.print(" ");
+ pw.print(KEY_DEFAULT_APPLICATION_START_INFO_ENABLED);
+ pw.print("=");
+ pw.println(mFlagApplicationStartInfoEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED); pw.print("=");
pw.println(mFlagBackgroundActivityStartsEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b7985a5..669be1a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -184,6 +184,7 @@
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
+import android.app.ApplicationStartInfo;
import android.app.ApplicationThreadConstants;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
@@ -192,6 +193,7 @@
import android.app.ForegroundServiceDelegationOptions;
import android.app.IActivityController;
import android.app.IActivityManager;
+import android.app.IApplicationStartInfoCompleteListener;
import android.app.IApplicationThread;
import android.app.IForegroundServiceObserver;
import android.app.IInstrumentationWatcher;
@@ -9452,6 +9454,37 @@
}
@Override
+ public ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(
+ String packageName, int maxNum, int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return new ParceledListSlice<ApplicationStartInfo>(
+ new ArrayList<ApplicationStartInfo>());
+ }
+ enforceNotIsolatedCaller("getHistoricalProcessStartReasons");
+
+ final ArrayList<ApplicationStartInfo> results = new ArrayList<ApplicationStartInfo>();
+
+ return new ParceledListSlice<ApplicationStartInfo>(results);
+ }
+
+ @Override
+ public void setApplicationStartInfoCompleteListener(
+ IApplicationStartInfoCompleteListener listener, int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return;
+ }
+ enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
+ }
+
+ @Override
+ public void removeApplicationStartInfoCompleteListener(int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return;
+ }
+ enforceNotIsolatedCaller("removeApplicationStartInfoCompleteListener");
+ }
+
+ @Override
public ParceledListSlice<ApplicationExitInfo> getHistoricalProcessExitReasons(
String packageName, int pid, int maxNum, int userId) {
enforceNotIsolatedCaller("getHistoricalProcessExitReasons");
@@ -16851,13 +16884,14 @@
@Override
public boolean startProfile(@UserIdInt int userId) {
- return mUserController.startProfile(userId);
+ return mUserController.startProfile(userId, /* evenWhenDisabled= */ false,
+ /* unlockListener= */ null);
}
@Override
public boolean startProfileWithListener(@UserIdInt int userId,
@Nullable IProgressListener unlockListener) {
- return mUserController.startProfile(userId, unlockListener);
+ return mUserController.startProfile(userId, /* evenWhenDisabled= */ false, unlockListener);
}
@Override
@@ -18456,6 +18490,12 @@
// has a SHORT_FGS.
return mOomAdjuster.hasUidShortForegroundService(uid);
}
+
+ @Override
+ public boolean startProfileEvenWhenDisabled(@UserIdInt int userId) {
+ return mUserController.startProfile(userId, /* evenWhenDisabled= */ true,
+ /* unlockListener= */ null);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index d29c327..05cf5dbb 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -229,14 +229,19 @@
* When defined, this receiver is considered "blocked" until at least the
* given count of other receivers have reached a terminal state; typically
* used for ordered broadcasts and priority traunches.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+ @Nullable
+ public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record,
+ int recordIndex, boolean wouldBeSkipped) {
if (record.isReplacePending()) {
- final boolean didReplace = replaceBroadcast(record, recordIndex,
- replacedBroadcastConsumer, wouldBeSkipped);
- if (didReplace) {
- return;
+ final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex,
+ wouldBeSkipped);
+ if (replacedBroadcastRecord != null) {
+ return replacedBroadcastRecord;
}
}
@@ -253,34 +258,37 @@
// with implicit responsiveness expectations.
getQueueForBroadcast(record).addLast(newBroadcastArgs);
onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
+ return null;
}
/**
* Searches from newest to oldest in the pending broadcast queues, and at the first matching
* pending broadcast it finds, replaces it in-place and returns -- does not attempt to handle
* "duplicate" broadcasts in the queue.
- * <p>
- * @return {@code true} if it found and replaced an existing record in the queue;
- * {@code false} otherwise.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- private boolean replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+ @Nullable
+ private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
+ boolean wouldBeSkipped) {
final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record);
- return replaceBroadcastInQueue(queue, record, recordIndex,
- replacedBroadcastConsumer, wouldBeSkipped);
+ return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped);
}
/**
* Searches from newest to oldest, and at the first matching pending broadcast
* it finds, replaces it in-place and returns -- does not attempt to handle
* "duplicate" broadcasts in the queue.
- * <p>
- * @return {@code true} if it found and replaced an existing record in the queue;
- * {@code false} otherwise.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
+ @Nullable
+ private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer,
boolean wouldBeSkipped) {
final Iterator<SomeArgs> it = queue.descendingIterator();
final Object receiver = record.receivers.get(recordIndex);
@@ -302,11 +310,10 @@
record.copyEnqueueTimeFrom(testRecord);
onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
- replacedBroadcastConsumer.accept(testRecord, testRecordIndex);
- return true;
+ return testRecord;
}
}
- return false;
+ return null;
}
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index f954420..d4d6eb2 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -92,6 +92,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -204,6 +205,14 @@
@GuardedBy("mService")
private final ArrayList<Pair<BooleanSupplier, CountDownLatch>> mWaitingFor = new ArrayList<>();
+ /**
+ * Container for holding the set of broadcasts that have been replaced by a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING}.
+ */
+ @GuardedBy("mService")
+ private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
+ new AtomicReference<>();
+
private final BroadcastConstants mConstants;
private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants;
@@ -627,9 +636,10 @@
r.enqueueRealTime = SystemClock.elapsedRealtime();
r.enqueueClockTime = System.currentTimeMillis();
- final ArraySet<BroadcastRecord> replacedBroadcasts = new ArraySet<>();
- final BroadcastConsumer replacedBroadcastConsumer =
- (record, i) -> replacedBroadcasts.add(record);
+ ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null);
+ if (replacedBroadcasts == null) {
+ replacedBroadcasts = new ArraySet<>();
+ }
boolean enqueuedBroadcast = false;
for (int i = 0; i < r.receivers.size(); i++) {
@@ -653,7 +663,11 @@
}
}
enqueuedBroadcast = true;
- queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer, wouldBeSkipped);
+ final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
+ r, i, wouldBeSkipped);
+ if (replacedBroadcast != null) {
+ replacedBroadcasts.add(replacedBroadcast);
+ }
if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) {
setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED,
"deferred at enqueue time");
@@ -664,7 +678,11 @@
// Skip any broadcasts that have been replaced by newer broadcasts with
// FLAG_RECEIVER_REPLACE_PENDING.
+ // TODO: Optimize and reuse mBroadcastConsumerSkipAndCanceled for the case of
+ // cancelling all receivers for a broadcast.
skipAndCancelReplacedBroadcasts(replacedBroadcasts);
+ replacedBroadcasts.clear();
+ mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);
// If nothing to dispatch, send any pending result immediately
if (r.receivers.isEmpty() || !enqueuedBroadcast) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8b34fe0..14ecf9f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -376,7 +376,7 @@
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER,
- true);
+ false); // assume false if the property is unknown
}
/**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b0a14ab..652f84d 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -55,6 +55,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -1463,18 +1464,24 @@
}
/**
- * Starts a user only if it's a profile, with a more relaxed permission requirement:
- * {@link android.Manifest.permission#MANAGE_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
- * To be called from ActivityManagerService.
- * @param userId the id of the user to start.
- * @return true if the operation was successful.
+ * Starts a {@link UserManager#isProfile() profile user}.
+ *
+ * <p>To be called from {@link com.android.server.am.ActivityManagerService}.
+ *
+ * @param userId the id of the profile user to start.
+ * @param evenWhenDisabled whether the profile should be started if it's not enabled yet
+ * (most callers should pass {@code false}, except when starting the profile while it's
+ * being provisioned).
+ * @param unlockListener listener to be informed when the profile has started and unlocked.
+ *
+ * @return {@code true} if the operation was successful.
+ *
+ * @throws IllegalArgumentException if the user doesn't exist or is not a profile.
*/
- boolean startProfile(@UserIdInt int userId) {
- return startProfile(userId, /* unlockListener= */ null);
- }
-
- boolean startProfile(@UserIdInt int userId, @Nullable IProgressListener unlockListener) {
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ boolean startProfile(@UserIdInt int userId, boolean evenWhenDisabled,
+ @Nullable IProgressListener unlockListener) {
if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
== PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -1489,8 +1496,8 @@
throw new IllegalArgumentException("User " + userId + " is not a profile");
}
- if (!userInfo.isEnabled()) {
- Slogf.w(TAG, "Cannot start disabled profile #" + userId);
+ if (!userInfo.isEnabled() && !evenWhenDisabled) {
+ Slogf.w(TAG, "Cannot start disabled profile #%d", userId);
return false;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e55bddb..e48c538 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2402,10 +2402,6 @@
Log.w(TAG, "audioFormat to enable is not a surround format.");
return false;
}
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Missing WRITE_SETTINGS permission");
- }
final long token = Binder.clearCallingIdentity();
try {
@@ -2473,11 +2469,6 @@
/** @see AudioManager#getEncodedSurroundMode() */
@Override
public int getEncodedSurroundMode(int targetSdkVersion) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Missing WRITE_SETTINGS permission");
- }
-
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSettingsLock) {
diff --git a/services/core/java/com/android/server/display/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
index f229d0f..a1081b2 100644
--- a/services/core/java/com/android/server/display/DisplayControl.java
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -37,6 +37,7 @@
private static native void nativeSetHdrConversionMode(int conversionMode,
int preferredHdrOutputType, int[] autoHdrTypes, int autoHdrTypesLength);
private static native int[] nativeGetSupportedHdrOutputTypes();
+ private static native boolean nativeGetHdrOutputConversionSupport();
/**
* Create a display in SurfaceFlinger.
@@ -118,4 +119,11 @@
public static @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypes() {
return nativeGetSupportedHdrOutputTypes();
}
+
+ /**
+ * @hide
+ */
+ public static boolean getHdrOutputConversionSupport() {
+ return nativeGetHdrOutputConversionSupport();
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e200d12..49bf0f5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -247,6 +247,8 @@
// HDR conversion mode chosen by user
@GuardedBy("mSyncRoot")
private HdrConversionMode mHdrConversionMode = null;
+ // Actual HDR conversion mode, which takes app overrides into account.
+ private HdrConversionMode mOverrideHdrConversionMode = null;
// The synchronization root for the display manager.
// This lock guards most of the display manager's state.
@@ -2025,12 +2027,23 @@
if (hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM) {
autoHdrOutputTypes = getEnabledAutoHdrTypesLocked();
}
- mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
- hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+
+ if (!mInjector.getHdrOutputConversionSupport()) {
+ return;
+ }
+ // If the HDR conversion is disabled by an app through WindowManager.LayoutParams, then
+ // set HDR conversion mode to HDR_CONVERSION_PASSTHROUGH.
+ if (mOverrideHdrConversionMode == null) {
+ mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
+ hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+ } else {
+ mInjector.setHdrConversionMode(mOverrideHdrConversionMode.getConversionMode(),
+ mOverrideHdrConversionMode.getPreferredHdrOutputType(), null);
+ }
}
}
- private HdrConversionMode getHdrConversionModeInternal() {
+ private HdrConversionMode getHdrConversionModeSettingInternal() {
synchronized (mSyncRoot) {
if (mHdrConversionMode != null) {
return mHdrConversionMode;
@@ -2039,6 +2052,16 @@
return new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
}
+ private HdrConversionMode getHdrConversionModeInternal() {
+ HdrConversionMode mode;
+ synchronized (mSyncRoot) {
+ mode = mOverrideHdrConversionMode != null
+ ? mOverrideHdrConversionMode
+ : mHdrConversionMode;
+ }
+ return mode != null ? mode : new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
+ }
+
private @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypesInternal() {
if (mSupportedHdrOutputType == null) {
mSupportedHdrOutputType = mInjector.getSupportedHdrOutputTypes();
@@ -2181,7 +2204,7 @@
private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean preferMinimalPostProcessing,
- boolean inTraversal) {
+ boolean disableHdrConversion, boolean inTraversal) {
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
if (display == null) {
@@ -2226,6 +2249,20 @@
if (shouldScheduleTraversal) {
scheduleTraversalLocked(inTraversal);
}
+
+ if (mHdrConversionMode == null) {
+ return;
+ }
+ if (mOverrideHdrConversionMode == null && disableHdrConversion) {
+ mOverrideHdrConversionMode =
+ new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH);
+ setHdrConversionModeInternal(mHdrConversionMode);
+ handleLogicalDisplayChangedLocked(display);
+ } else if (mOverrideHdrConversionMode != null && !disableHdrConversion) {
+ mOverrideHdrConversionMode = null;
+ setHdrConversionModeInternal(mHdrConversionMode);
+ handleLogicalDisplayChangedLocked(display);
+ }
}
}
@@ -2783,6 +2820,10 @@
int[] getSupportedHdrOutputTypes() {
return DisplayControl.getSupportedHdrOutputTypes();
}
+
+ boolean getHdrOutputConversionSupport() {
+ return DisplayControl.getHdrOutputConversionSupport();
+ }
}
@VisibleForTesting
@@ -3757,6 +3798,16 @@
}
@Override // Binder call
+ public HdrConversionMode getHdrConversionModeSetting() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getHdrConversionModeSettingInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public HdrConversionMode getHdrConversionMode() {
final long token = Binder.clearCallingIdentity();
try {
@@ -4030,10 +4081,10 @@
public void setDisplayProperties(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
- boolean inTraversal) {
+ boolean disableHdrConversion, boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
- requestedMinimalPostProcessing, inTraversal);
+ requestedMinimalPostProcessing, disableHdrConversion, inTraversal);
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
index 3a25146..f5114b7 100644
--- a/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
+++ b/services/core/java/com/android/server/location/gnss/NetworkTimeHelper.java
@@ -32,6 +32,14 @@
abstract class NetworkTimeHelper {
/**
+ * This compile-time value can be changed to switch between new and old ways to obtain network
+ * time for GNSS. If you have to turn this from {@code true} to {@code false} then please create
+ * a platform bug. This switch will be removed in a future release. If there are problems with
+ * the new impl we'd like to hear about them.
+ */
+ static final boolean USE_TIME_DETECTOR_IMPL = false;
+
+ /**
* The callback interface used by {@link NetworkTimeHelper} to report the time to {@link
* GnssLocationProvider}. The callback can happen at any time using the thread associated with
* the looper passed to {@link #create(Context, Looper, InjectTimeCallback)}.
@@ -47,7 +55,13 @@
static NetworkTimeHelper create(
@NonNull Context context, @NonNull Looper looper,
@NonNull InjectTimeCallback injectTimeCallback) {
- return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
+ if (USE_TIME_DETECTOR_IMPL) {
+ TimeDetectorNetworkTimeHelper.Environment environment =
+ new TimeDetectorNetworkTimeHelper.EnvironmentImpl(looper);
+ return new TimeDetectorNetworkTimeHelper(environment, injectTimeCallback);
+ } else {
+ return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
+ }
}
/**
@@ -74,7 +88,9 @@
* Notifies that network connectivity has been established.
*
* <p>Called by {@link GnssLocationProvider} when the device establishes a data network
- * connection.
+ * connection. This call should be removed eventually because it should be handled by the {@link
+ * NetworkTimeHelper} implementation itself, but has been retained for compatibility while
+ * switching implementations.
*/
abstract void onNetworkAvailable();
@@ -82,4 +98,5 @@
* Dumps internal state during bugreports useful for debugging.
*/
abstract void dump(@NonNull PrintWriter pw);
+
}
diff --git a/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java b/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java
new file mode 100644
index 0000000..15366d3
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/TimeDetectorNetworkTimeHelper.java
@@ -0,0 +1,339 @@
+/*
+ * 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.server.location.gnss;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.time.UnixEpochTime;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.timedetector.NetworkTimeSuggestion;
+import com.android.server.timedetector.TimeDetectorInternal;
+import com.android.server.timezonedetector.StateChangeListener;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Handles injecting network time to GNSS by using information from the platform time detector.
+ */
+public class TimeDetectorNetworkTimeHelper extends NetworkTimeHelper {
+
+ /** Returns {@code true} if the TimeDetectorNetworkTimeHelper is being used. */
+ public static boolean isInUse() {
+ return NetworkTimeHelper.USE_TIME_DETECTOR_IMPL;
+ }
+
+ /**
+ * An interface exposed for easier testing that the surrounding class uses for interacting with
+ * platform services, handlers, etc.
+ */
+ interface Environment {
+
+ /**
+ * Returns the current elapsed realtime value. The same as calling {@link
+ * SystemClock#elapsedRealtime()} but easier to fake in tests.
+ */
+ @ElapsedRealtimeLong long elapsedRealtimeMillis();
+
+ /**
+ * Returns the latest / best network time available from the time detector service.
+ */
+ @Nullable NetworkTimeSuggestion getLatestNetworkTime();
+
+ /**
+ * Sets a listener that will receive a callback when the value returned by {@link
+ * #getLatestNetworkTime()} has changed.
+ */
+ void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener);
+
+ /**
+ * Requests asynchronous execution of {@link
+ * TimeDetectorNetworkTimeHelper#queryAndInjectNetworkTime}, to execute as soon as possible.
+ * The thread used is the same as used by {@link #requestDelayedTimeQueryCallback}.
+ * Only one immediate callback can be requested at a time; requesting a new immediate
+ * callback will clear any previously requested one.
+ */
+ void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper, String reason);
+
+ /**
+ * Requests a delayed call to
+ * {@link TimeDetectorNetworkTimeHelper#delayedQueryAndInjectNetworkTime()}.
+ * The thread used is the same as used by {@link #requestImmediateTimeQueryCallback}.
+ * Only one delayed callback can be scheduled at a time; requesting a new delayed callback
+ * will clear any previously requested one.
+ */
+ void requestDelayedTimeQueryCallback(
+ TimeDetectorNetworkTimeHelper helper, @DurationMillisLong long delayMillis);
+
+ /**
+ * Clear a delayed time query callback. This has no effect if no delayed callback is
+ * currently set.
+ */
+ void clearDelayedTimeQueryCallback();
+ }
+
+ private static final String TAG = "TDNetworkTimeHelper";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /** The maximum age of a network time signal that will be passed to GNSS. */
+ @VisibleForTesting
+ static final int MAX_NETWORK_TIME_AGE_MILLIS = 24 * 60 * 60 * 1000;
+
+ /**
+ * The maximum time that is allowed to pass before a network time signal should be evaluated to
+ * be passed to GNSS when mOnDemandTimeInjection == false.
+ */
+ static final int NTP_REFRESH_INTERVAL_MILLIS = MAX_NETWORK_TIME_AGE_MILLIS;
+
+ private final LocalLog mDumpLog = new LocalLog(10, /*useLocalTimestamps=*/false);
+
+ /** The object the helper uses to interact with other components. */
+ @NonNull private final Environment mEnvironment;
+ @NonNull private final InjectTimeCallback mInjectTimeCallback;
+
+ /** Set to true if the GNSS engine requested on-demand NTP time injections. */
+ @GuardedBy("this")
+ private boolean mPeriodicTimeInjectionEnabled;
+
+ /**
+ * Set to true when a network time has been injected. Used to ensure that a network time is
+ * injected if this object wasn't listening when a network time signal first became available.
+ */
+ @GuardedBy("this")
+ private boolean mNetworkTimeInjected;
+
+ TimeDetectorNetworkTimeHelper(
+ @NonNull Environment environment, @NonNull InjectTimeCallback injectTimeCallback) {
+ mInjectTimeCallback = Objects.requireNonNull(injectTimeCallback);
+ mEnvironment = Objects.requireNonNull(environment);
+
+ // Start listening for new network time updates immediately.
+ mEnvironment.setNetworkTimeUpdateListener(this::onNetworkTimeAvailable);
+ }
+
+ @Override
+ synchronized void setPeriodicTimeInjectionMode(boolean periodicTimeInjectionEnabled) {
+ // Periodic time injection has a complicated history. See b/73893222. When it is true, it
+ // doesn't mean ONLY send it periodically.
+ //
+ // periodicTimeInjectionEnabled == true means the GNSS would like to be told the time
+ // periodically in addition to all the other triggers (e.g. network available).
+
+ mPeriodicTimeInjectionEnabled = periodicTimeInjectionEnabled;
+ if (!periodicTimeInjectionEnabled) {
+ // Cancel any previously scheduled periodic query.
+ removePeriodicNetworkTimeQuery();
+ }
+
+ // Inject the latest network time in all cases if it is available.
+ // Calling queryAndInjectNetworkTime() will cause a time signal to be injected if one is
+ // available AND will cause the next periodic query to be scheduled.
+ String reason = "setPeriodicTimeInjectionMode(" + periodicTimeInjectionEnabled + ")";
+ mEnvironment.requestImmediateTimeQueryCallback(this, reason);
+ }
+
+ void onNetworkTimeAvailable() {
+ // A new network time could become available at any time. Make sure it is passed to GNSS.
+ mEnvironment.requestImmediateTimeQueryCallback(this, "onNetworkTimeAvailable");
+ }
+
+ @Override
+ void onNetworkAvailable() {
+ // In the original NetworkTimeHelper implementation, onNetworkAvailable() would cause an NTP
+ // refresh to be made if it had previously been blocked by network issues. This
+ // implementation generally relies on components associated with the time detector to
+ // monitor the network and call onNetworkTimeAvailable() when a time is available. However,
+ // it also checks mNetworkTimeInjected in case this component wasn't listening for
+ // onNetworkTimeAvailable() when the last one became available.
+ synchronized (this) {
+ if (!mNetworkTimeInjected) {
+ // Guard against ordering issues: This check should ensure that if a network time
+ // became available before this class started listening then the initial network
+ // time will still be injected.
+ mEnvironment.requestImmediateTimeQueryCallback(this, "onNetworkAvailable");
+ }
+ }
+ }
+
+ @Override
+ void demandUtcTimeInjection() {
+ mEnvironment.requestImmediateTimeQueryCallback(this, "demandUtcTimeInjection");
+ }
+
+ // This method should always be invoked on the mEnvironment thread.
+ void delayedQueryAndInjectNetworkTime() {
+ queryAndInjectNetworkTime("delayedTimeQueryCallback");
+ }
+
+ // This method should always be invoked on the mEnvironment thread.
+ synchronized void queryAndInjectNetworkTime(@NonNull String reason) {
+ NetworkTimeSuggestion latestNetworkTime = mEnvironment.getLatestNetworkTime();
+
+ maybeInjectNetworkTime(latestNetworkTime, reason);
+
+ // Deschedule (if needed) any previously scheduled periodic query.
+ removePeriodicNetworkTimeQuery();
+
+ if (mPeriodicTimeInjectionEnabled) {
+ int maxDelayMillis = NTP_REFRESH_INTERVAL_MILLIS;
+ String debugMsg = "queryAndInjectNtpTime: Scheduling periodic query"
+ + " reason=" + reason
+ + " latestNetworkTime=" + latestNetworkTime
+ + " maxDelayMillis=" + maxDelayMillis;
+ logToDumpLog(debugMsg);
+
+ // GNSS is expecting periodic injections, so schedule the next one.
+ mEnvironment.requestDelayedTimeQueryCallback(this, maxDelayMillis);
+ }
+ }
+
+ private long calculateTimeSignalAgeMillis(
+ @Nullable NetworkTimeSuggestion networkTimeSuggestion) {
+ if (networkTimeSuggestion == null) {
+ return Long.MAX_VALUE;
+ }
+
+ long suggestionElapsedRealtimeMillis =
+ networkTimeSuggestion.getUnixEpochTime().getElapsedRealtimeMillis();
+ long currentElapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
+ return currentElapsedRealtimeMillis - suggestionElapsedRealtimeMillis;
+ }
+
+ @GuardedBy("this")
+ private void maybeInjectNetworkTime(
+ @Nullable NetworkTimeSuggestion latestNetworkTime, @NonNull String reason) {
+ // Historically, time would only be injected if it was under a certain age. This has been
+ // kept in case it is assumed by GNSS implementations.
+ if (calculateTimeSignalAgeMillis(latestNetworkTime) > MAX_NETWORK_TIME_AGE_MILLIS) {
+ String debugMsg = "maybeInjectNetworkTime: Not injecting latest network time"
+ + " latestNetworkTime=" + latestNetworkTime
+ + " reason=" + reason;
+ logToDumpLog(debugMsg);
+ return;
+ }
+
+ UnixEpochTime unixEpochTime = latestNetworkTime.getUnixEpochTime();
+ long unixEpochTimeMillis = unixEpochTime.getUnixEpochTimeMillis();
+ long currentTimeMillis = System.currentTimeMillis();
+ String debugMsg = "maybeInjectNetworkTime: Injecting latest network time"
+ + " latestNetworkTime=" + latestNetworkTime
+ + " reason=" + reason
+ + " System time offset millis=" + (unixEpochTimeMillis - currentTimeMillis);
+ logToDumpLog(debugMsg);
+
+ long timeReferenceMillis = unixEpochTime.getElapsedRealtimeMillis();
+ int uncertaintyMillis = latestNetworkTime.getUncertaintyMillis();
+ mInjectTimeCallback.injectTime(unixEpochTimeMillis, timeReferenceMillis, uncertaintyMillis);
+ mNetworkTimeInjected = true;
+ }
+
+ @Override
+ void dump(@NonNull PrintWriter pw) {
+ pw.println("TimeDetectorNetworkTimeHelper:");
+
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+ synchronized (this) {
+ ipw.println("mPeriodicTimeInjectionEnabled=" + mPeriodicTimeInjectionEnabled);
+ }
+
+ ipw.println("Debug log:");
+ mDumpLog.dump(ipw);
+ }
+
+ private void logToDumpLog(@NonNull String message) {
+ mDumpLog.log(message);
+ if (DEBUG) {
+ Log.d(TAG, message);
+ }
+ }
+
+ private void removePeriodicNetworkTimeQuery() {
+ // De-schedule any previously scheduled refresh. This is idempotent and has no effect if
+ // there isn't one.
+ mEnvironment.clearDelayedTimeQueryCallback();
+ }
+
+ /** The real implementation of {@link Environment} used outside of tests. */
+ static class EnvironmentImpl implements Environment {
+
+ /** Used to ensure one scheduled runnable is queued at a time. */
+ private final Object mScheduledRunnableToken = new Object();
+ /** Used to ensure one immediate runnable is queued at a time. */
+ private final Object mImmediateRunnableToken = new Object();
+ private final Handler mHandler;
+ private final TimeDetectorInternal mTimeDetectorInternal;
+
+ EnvironmentImpl(Looper looper) {
+ mHandler = new Handler(looper);
+ mTimeDetectorInternal = LocalServices.getService(TimeDetectorInternal.class);
+ }
+
+ @Override
+ public long elapsedRealtimeMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public NetworkTimeSuggestion getLatestNetworkTime() {
+ return mTimeDetectorInternal.getLatestNetworkSuggestion();
+ }
+
+ @Override
+ public void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener) {
+ mTimeDetectorInternal.addNetworkTimeUpdateListener(stateChangeListener);
+ }
+
+ @Override
+ public void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+ String reason) {
+ // Ensure only one immediate callback is scheduled at a time. There's no
+ // post(Runnable, Object), so we postDelayed() with a zero wait.
+ synchronized (this) {
+ mHandler.removeCallbacksAndMessages(mImmediateRunnableToken);
+ mHandler.postDelayed(() -> helper.queryAndInjectNetworkTime(reason),
+ mImmediateRunnableToken, 0);
+ }
+ }
+
+ @Override
+ public void requestDelayedTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+ long delayMillis) {
+ synchronized (this) {
+ clearDelayedTimeQueryCallback();
+ mHandler.postDelayed(helper::delayedQueryAndInjectNetworkTime,
+ mScheduledRunnableToken, delayMillis);
+ }
+ }
+
+ @Override
+ public synchronized void clearDelayedTimeQueryCallback() {
+ mHandler.removeCallbacksAndMessages(mScheduledRunnableToken);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 25efe0c..77b9abe 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -287,19 +287,16 @@
if (packageName == null || packageName.isEmpty()) {
throw new IllegalArgumentException("package name must not be empty");
}
-
- final UserHandle callingUser = Binder.getCallingUserHandle();
- final long callingToken = Binder.clearCallingIdentity();
+ final ApplicationInfo ai;
+ try {
+ ai = mPackageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No package matching :" + packageName);
+ }
MediaProjection projection;
+ final long callingToken = Binder.clearCallingIdentity();
try {
- ApplicationInfo ai;
- try {
- ai = mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);
- } catch (NameNotFoundException e) {
- throw new IllegalArgumentException("No package matching :" + packageName);
- }
-
projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion,
ai.isPrivilegedApp());
if (isPermanentGrant) {
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index f989f6f..c3cc392 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -153,7 +153,7 @@
mInstallSource = installSource;
mVolumeUuid = sessionParams.volumeUuid;
mPackageAbiOverride = sessionParams.abiOverride;
- mPermissionStates = sessionParams.getFinalPermissionStates();
+ mPermissionStates = sessionParams.getPermissionStates();
mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
mSigningDetails = signingDetails;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index e254300..85d2df3 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -388,7 +388,7 @@
if (abi32 >= 0) {
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
if (abi64 >= 0) {
- if (pkg.isUse32BitAbi()) {
+ if (pkg.is32BitAbiPreferred()) {
secondaryCpuAbi = primaryCpuAbi;
primaryCpuAbi = abi;
} else {
@@ -474,7 +474,8 @@
private boolean shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp,
boolean isUpdatedSystemApp) {
// We shouldn't extract libs if the package is a library or if extractNativeLibs=false
- boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg) && pkg.isExtractNativeLibs();
+ boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg)
+ && pkg.isExtractNativeLibrariesRequested();
// We shouldn't attempt to extract libs from system app when it was not updated.
if (isSystemApp && !isUpdatedSystemApp) {
extractLibs = false;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f708fbb..f338137 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -189,7 +189,7 @@
}
// We do not dexopt a package with no code.
- if (!pkg.isHasCode()) {
+ if (!pkg.isDeclaredHavingCode()) {
return false;
}
@@ -287,7 +287,7 @@
// For each code path in the package, this array contains the class loader context that
// needs to be passed to dexopt in order to ensure correct optimizations.
boolean[] pathsWithCode = new boolean[paths.size()];
- pathsWithCode[0] = pkg.isHasCode();
+ pathsWithCode[0] = pkg.isDeclaredHavingCode();
for (int i = 1; i < paths.size(); i++) {
pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed9d370..0897289 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -804,7 +804,7 @@
+ " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag");
}
- var permissionStates = params.getFinalPermissionStates();
+ var permissionStates = params.getPermissionStates();
if (!permissionStates.isEmpty()) {
if (!hasInstallGrantRuntimePermissions) {
for (int index = 0; index < permissionStates.size(); index++) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ad3af3e..3951903 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -4878,7 +4878,16 @@
private static void writePermissionsLocked(@NonNull TypedXmlSerializer out,
@NonNull SessionParams params) throws IOException {
- params.writePermissionStateXml(out, TAG_GRANT_PERMISSION, TAG_DENY_PERMISSION, ATTR_NAME);
+ var permissionStates = params.getPermissionStates();
+ for (int index = 0; index < permissionStates.size(); index++) {
+ var permissionName = permissionStates.keyAt(index);
+ var state = permissionStates.valueAt(index);
+ String tag = state == SessionParams.PERMISSION_STATE_GRANTED ? TAG_GRANT_PERMISSION
+ : TAG_DENY_PERMISSION;
+ out.startTag(null, tag);
+ writeStringAttribute(out, ATTR_NAME, permissionName);
+ out.endTag(null, tag);
+ }
}
private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull TypedXmlSerializer out,
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 2538871..e4f3e2b 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -547,7 +547,7 @@
*/
public static void assertCodePolicy(AndroidPackage pkg)
throws PackageManagerException {
- final boolean shouldHaveCode = pkg.isHasCode();
+ final boolean shouldHaveCode = pkg.isDeclaredHavingCode();
if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package " + pkg.getBaseApkPath() + " code is missing");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6541b40..f1998f7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4864,7 +4864,7 @@
pw.println();
if (pkg != null) {
pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName());
- pw.print(prefix); pw.print(" usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
+ pw.print(prefix); pw.print(" usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, pkg); pw.println();
final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
@@ -4897,25 +4897,25 @@
pw.print(prefix); pw.print(" dataDir="); pw.println(dataDir.getAbsolutePath());
pw.print(prefix); pw.print(" supportsScreens=[");
boolean first = true;
- if (pkg.isSupportsSmallScreens()) {
+ if (pkg.isSmallScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("small");
}
- if (pkg.isSupportsNormalScreens()) {
+ if (pkg.isNormalScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("medium");
}
- if (pkg.isSupportsLargeScreens()) {
+ if (pkg.isLargeScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("large");
}
- if (pkg.isSupportsExtraLargeScreens()) {
+ if (pkg.isExtraLargeScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a22ea96..317c111 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1362,15 +1362,14 @@
}
try {
if (enableQuietMode) {
- ActivityManager.getService().stopUser(userId, /* force */true, null);
+ ActivityManager.getService().stopUser(userId, /* force= */ true, null);
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userId);
} else {
IProgressListener callback = target != null
? new DisableQuietModeUserUnlockedCallback(target)
: null;
- ActivityManager.getService().startUserInBackgroundWithListener(
- userId, callback);
+ ActivityManager.getService().startProfileWithListener(userId, callback);
}
logQuietModeEnabled(userId, enableQuietMode, callingPackage);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index d8b6cd5..d88b66b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -580,7 +580,7 @@
*/
private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
ArrayMap<String, String> result = new ArrayMap<>();
- if (pkg.isHasCode()) {
+ if (pkg.isDeclaredHavingCode()) {
result.put(pkg.getBaseApkPath(), ArtManager.getProfileName(null));
}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index a3be8d3..d108e14 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -133,7 +133,7 @@
info.splitRevisionCodes = pkg.getSplitRevisionCodes();
info.versionName = pkg.getVersionName();
info.sharedUserId = pkg.getSharedUserId();
- info.sharedUserLabel = pkg.getSharedUserLabelRes();
+ info.sharedUserLabel = pkg.getSharedUserLabelResourceId();
info.applicationInfo = applicationInfo;
info.installLocation = pkg.getInstallLocation();
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
@@ -876,27 +876,27 @@
// @formatter:off
int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
| flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
- | flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
- | flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+ | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+ | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
| flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
| flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
| flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
| flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
| flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
- | flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
- | flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
- | flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+ | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+ | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
| flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
- | flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
- | flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+ | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+ | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
| flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
| flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
- | flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+ | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
| flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
- | flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
- | flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
- | flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
- | flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+ | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+ | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+ | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+ | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
| flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
@@ -932,12 +932,12 @@
| flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
| flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
| flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
- | flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+ | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
| flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
| flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
- | flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
- | flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
- | flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+ | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+ | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
| flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index f3ee531..e2acc17 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -59,7 +59,7 @@
AndroidPackage aPkg) {
PackageImpl pkg = (PackageImpl) aPkg;
ArrayList<String> paths = new ArrayList<>();
- if (pkg.isHasCode()) {
+ if (pkg.isDeclaredHavingCode()) {
paths.add(pkg.getBaseApkPath());
}
String[] splitCodePaths = pkg.getSplitCodePaths();
@@ -156,7 +156,7 @@
return NativeLibraryHelper.Handle.create(
AndroidPackageUtils.getAllCodePaths(pkg),
pkg.isMultiArch(),
- pkg.isExtractNativeLibs(),
+ pkg.isExtractNativeLibrariesRequested(),
pkg.isDebuggable()
);
}
@@ -243,7 +243,7 @@
} else if (pkg.isSignedWithPlatformKey()) {
isAllowedToUseHiddenApis = true;
} else if (packageState.isSystem()) {
- isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
+ isAllowedToUseHiddenApis = pkg.isNonSdkApiRequested()
|| SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
pkg.getPackageName());
} else {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index d7c4a09..de31b46 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -793,7 +793,7 @@
null,
getBaseApkPath(),
getBaseRevisionCode(),
- isHasCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
+ isDeclaredHavingCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
getClassLoaderName()
));
@@ -879,7 +879,7 @@
}
@Override
- public int getBannerRes() {
+ public int getBannerResourceId() {
return banner;
}
@@ -934,12 +934,12 @@
}
@Override
- public int getDataExtractionRulesRes() {
+ public int getDataExtractionRulesResourceId() {
return dataExtractionRules;
}
@Override
- public int getDescriptionRes() {
+ public int getDescriptionResourceId() {
return descriptionRes;
}
@@ -950,7 +950,7 @@
}
@Override
- public int getFullBackupContentRes() {
+ public int getFullBackupContentResourceId() {
return fullBackupContent;
}
@@ -961,7 +961,7 @@
}
@Override
- public int getIconRes() {
+ public int getIconResourceId() {
return iconRes;
}
@@ -995,7 +995,7 @@
}
@Override
- public int getLabelRes() {
+ public int getLabelResourceId() {
return labelRes;
}
@@ -1011,12 +1011,12 @@
}
@Override
- public int getLocaleConfigRes() {
+ public int getLocaleConfigResourceId() {
return mLocaleConfigRes;
}
@Override
- public int getLogoRes() {
+ public int getLogoResourceId() {
return logo;
}
@@ -1077,7 +1077,7 @@
}
@Override
- public int getNetworkSecurityConfigRes() {
+ public int getNetworkSecurityConfigResourceId() {
return networkSecurityConfigRes;
}
@@ -1259,7 +1259,7 @@
}
@Override
- public int getRoundIconRes() {
+ public int getRoundIconResourceId() {
return roundIconRes;
}
@@ -1287,7 +1287,7 @@
}
@Override
- public int getSharedUserLabelRes() {
+ public int getSharedUserLabelResourceId() {
return sharedUserLabel;
}
@@ -1366,7 +1366,7 @@
}
@Override
- public int getThemeRes() {
+ public int getThemeResourceId() {
return theme;
}
@@ -1531,17 +1531,17 @@
}
@Override
- public boolean isAllowBackup() {
+ public boolean isBackupAllowed() {
return getBoolean(Booleans.ALLOW_BACKUP);
}
@Override
- public boolean isAllowClearUserData() {
+ public boolean isClearUserDataAllowed() {
return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA);
}
@Override
- public boolean isAllowClearUserDataOnFailedRestore() {
+ public boolean isClearUserDataOnFailedRestoreAllowed() {
return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE);
}
@@ -1551,7 +1551,7 @@
}
@Override
- public boolean isAllowTaskReparenting() {
+ public boolean isTaskReparentingAllowed() {
return getBoolean(Booleans.ALLOW_TASK_REPARENTING);
}
@@ -1574,7 +1574,7 @@
}
@Override
- public boolean isCantSaveState() {
+ public boolean isSaveStateDisallowed() {
return getBoolean(Booleans.CANT_SAVE_STATE);
}
@@ -1609,7 +1609,7 @@
}
@Override
- public boolean isExtractNativeLibs() {
+ public boolean isExtractNativeLibrariesRequested() {
return getBoolean(Booleans.EXTRACT_NATIVE_LIBS);
}
@@ -1629,7 +1629,7 @@
}
@Override
- public boolean isHasCode() {
+ public boolean isDeclaredHavingCode() {
return getBoolean(Booleans.HAS_CODE);
}
@@ -1639,7 +1639,7 @@
}
@Override
- public boolean isHasFragileUserData() {
+ public boolean isUserDataFragile() {
return getBoolean(Booleans.HAS_FRAGILE_USER_DATA);
}
@@ -1649,7 +1649,7 @@
}
@Override
- public boolean isKillAfterRestore() {
+ public boolean isKillAfterRestoreAllowed() {
return getBoolean(Booleans.KILL_AFTER_RESTORE);
}
@@ -1746,7 +1746,7 @@
return getBoolean(Booleans.STATIC_SHARED_LIBRARY);
}
- public boolean isSupportsExtraLargeScreens() {
+ public boolean isExtraLargeScreensSupported() {
if (supportsExtraLargeScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD;
}
@@ -1754,7 +1754,7 @@
return supportsExtraLargeScreens;
}
- public boolean isSupportsLargeScreens() {
+ public boolean isLargeScreensSupported() {
if (supportsLargeScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.DONUT;
}
@@ -1762,16 +1762,16 @@
return supportsLargeScreens;
}
- public boolean isSupportsNormalScreens() {
+ public boolean isNormalScreensSupported() {
return supportsNormalScreens == null || supportsNormalScreens;
}
@Override
- public boolean isSupportsRtl() {
+ public boolean isRtlSupported() {
return getBoolean(Booleans.SUPPORTS_RTL);
}
- public boolean isSupportsSmallScreens() {
+ public boolean isSmallScreensSupported() {
if (supportsSmallScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.DONUT;
}
@@ -1785,7 +1785,7 @@
}
@Override
- public boolean isUse32BitAbi() {
+ public boolean is32BitAbiPreferred() {
return getBoolean(Booleans.USE_32_BIT_ABI);
}
@@ -1795,12 +1795,12 @@
}
@Override
- public boolean isUsesCleartextTraffic() {
+ public boolean isCleartextTrafficAllowed() {
return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC);
}
@Override
- public boolean isUsesNonSdkApi() {
+ public boolean isNonSdkApiRequested() {
return getBoolean(Booleans.USES_NON_SDK_API);
}
@@ -1831,17 +1831,17 @@
}
@Override
- public PackageImpl setAllowBackup(boolean value) {
+ public PackageImpl setBackupAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_BACKUP, value);
}
@Override
- public PackageImpl setAllowClearUserData(boolean value) {
+ public PackageImpl setClearUserDataAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value);
}
@Override
- public PackageImpl setAllowClearUserDataOnFailedRestore(boolean value) {
+ public PackageImpl setClearUserDataOnFailedRestoreAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value);
}
@@ -1851,7 +1851,7 @@
}
@Override
- public PackageImpl setAllowTaskReparenting(boolean value) {
+ public PackageImpl setTaskReparentingAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value);
}
@@ -1895,7 +1895,7 @@
}
@Override
- public PackageImpl setBannerRes(int value) {
+ public PackageImpl setBannerResourceId(int value) {
banner = value;
return this;
}
@@ -1912,7 +1912,7 @@
}
@Override
- public PackageImpl setCantSaveState(boolean value) {
+ public PackageImpl setSaveStateDisallowed(boolean value) {
return setBoolean(Booleans.CANT_SAVE_STATE, value);
}
@@ -1958,7 +1958,7 @@
}
@Override
- public PackageImpl setDataExtractionRulesRes(int value) {
+ public PackageImpl setDataExtractionRulesResourceId(int value) {
dataExtractionRules = value;
return this;
}
@@ -1969,7 +1969,7 @@
}
@Override
- public PackageImpl setDescriptionRes(int value) {
+ public PackageImpl setDescriptionResourceId(int value) {
descriptionRes = value;
return this;
}
@@ -1985,7 +1985,7 @@
}
@Override
- public PackageImpl setExtractNativeLibs(boolean value) {
+ public PackageImpl setExtractNativeLibrariesRequested(boolean value) {
return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value);
}
@@ -1995,7 +1995,7 @@
}
@Override
- public PackageImpl setFullBackupContentRes(int value) {
+ public PackageImpl setFullBackupContentResourceId(int value) {
fullBackupContent = value;
return this;
}
@@ -2017,7 +2017,7 @@
}
@Override
- public PackageImpl setHasCode(boolean value) {
+ public PackageImpl setDeclaredHavingCode(boolean value) {
return setBoolean(Booleans.HAS_CODE, value);
}
@@ -2027,12 +2027,12 @@
}
@Override
- public PackageImpl setHasFragileUserData(boolean value) {
+ public PackageImpl setUserDataFragile(boolean value) {
return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value);
}
@Override
- public PackageImpl setIconRes(int value) {
+ public PackageImpl setIconResourceId(int value) {
iconRes = value;
return this;
}
@@ -2049,7 +2049,7 @@
}
@Override
- public PackageImpl setKillAfterRestore(boolean value) {
+ public PackageImpl setKillAfterRestoreAllowed(boolean value) {
return setBoolean(Booleans.KILL_AFTER_RESTORE, value);
}
@@ -2060,7 +2060,7 @@
}
@Override
- public PackageImpl setLabelRes(int value) {
+ public PackageImpl setLabelResourceId(int value) {
labelRes = value;
return this;
}
@@ -2082,13 +2082,13 @@
}
@Override
- public PackageImpl setLocaleConfigRes(int value) {
+ public PackageImpl setLocaleConfigResourceId(int value) {
mLocaleConfigRes = value;
return this;
}
@Override
- public PackageImpl setLogoRes(int value) {
+ public PackageImpl setLogoResourceId(int value) {
logo = value;
return this;
}
@@ -2154,7 +2154,7 @@
}
@Override
- public PackageImpl setNetworkSecurityConfigRes(int value) {
+ public PackageImpl setNetworkSecurityConfigResourceId(int value) {
networkSecurityConfigRes = value;
return this;
}
@@ -2318,7 +2318,7 @@
}
@Override
- public PackageImpl setRoundIconRes(int value) {
+ public PackageImpl setRoundIconResourceId(int value) {
roundIconRes = value;
return this;
}
@@ -2347,7 +2347,7 @@
}
@Override
- public PackageImpl setSharedUserLabelRes(int value) {
+ public PackageImpl setSharedUserLabelResourceId(int value) {
sharedUserLabel = value;
return this;
}
@@ -2384,7 +2384,7 @@
}
@Override
- public PackageImpl setSupportsExtraLargeScreens(int supportsExtraLargeScreens) {
+ public PackageImpl setExtraLargeScreensSupported(int supportsExtraLargeScreens) {
if (supportsExtraLargeScreens == 1) {
return this;
}
@@ -2394,7 +2394,7 @@
}
@Override
- public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+ public PackageImpl setLargeScreensSupported(int supportsLargeScreens) {
if (supportsLargeScreens == 1) {
return this;
}
@@ -2404,7 +2404,7 @@
}
@Override
- public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+ public PackageImpl setNormalScreensSupported(int supportsNormalScreens) {
if (supportsNormalScreens == 1) {
return this;
}
@@ -2414,12 +2414,12 @@
}
@Override
- public PackageImpl setSupportsRtl(boolean value) {
+ public PackageImpl setRtlSupported(boolean value) {
return setBoolean(Booleans.SUPPORTS_RTL, value);
}
@Override
- public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+ public PackageImpl setSmallScreensSupported(int supportsSmallScreens) {
if (supportsSmallScreens == 1) {
return this;
}
@@ -2452,7 +2452,7 @@
}
@Override
- public PackageImpl setThemeRes(int value) {
+ public PackageImpl setThemeResourceId(int value) {
theme = value;
return this;
}
@@ -2470,7 +2470,7 @@
}
@Override
- public PackageImpl setUse32BitAbi(boolean value) {
+ public PackageImpl set32BitAbiPreferred(boolean value) {
return setBoolean(Booleans.USE_32_BIT_ABI, value);
}
@@ -2480,12 +2480,12 @@
}
@Override
- public PackageImpl setUsesCleartextTraffic(boolean value) {
+ public PackageImpl setCleartextTrafficAllowed(boolean value) {
return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value);
}
@Override
- public PackageImpl setUsesNonSdkApi(boolean value) {
+ public PackageImpl setNonSdkApiRequested(boolean value) {
return setBoolean(Booleans.USES_NON_SDK_API, value);
}
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index ad73873..2fdda12 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -116,7 +116,7 @@
* @see R.styleable#AndroidManifestApplication_banner
*/
@DrawableRes
- int getBannerRes();
+ int getBannerResourceId();
/**
* @see PackageInfo#baseRevisionCode
@@ -149,21 +149,21 @@
* @see R.styleable#AndroidManifestApplication_dataExtractionRules
*/
@XmlRes
- int getDataExtractionRulesRes();
+ int getDataExtractionRulesResourceId();
/**
* @see ApplicationInfo#descriptionRes
* @see R.styleable#AndroidManifestApplication_description
*/
@StringRes // This is actually format="reference"
- int getDescriptionRes();
+ int getDescriptionResourceId();
/**
* @see ApplicationInfo#fullBackupContent
* @see R.styleable#AndroidManifestApplication_fullBackupContent
*/
@XmlRes
- int getFullBackupContentRes();
+ int getFullBackupContentResourceId();
/**
* @see ApplicationInfo#getGwpAsanMode()
@@ -177,14 +177,14 @@
* @see R.styleable#AndroidManifestApplication_icon
*/
@DrawableRes
- int getIconRes();
+ int getIconResourceId();
/**
* @see ApplicationInfo#labelRes
* @see R.styleable#AndroidManifestApplication_label
*/
@StringRes
- int getLabelRes();
+ int getLabelResourceId();
/**
* @see ApplicationInfo#largestWidthLimitDp
@@ -206,7 +206,7 @@
* @see R.styleable#AndroidManifestApplication_logo
*/
@DrawableRes
- int getLogoRes();
+ int getLogoResourceId();
/**
* The resource ID used to provide the application's locales configuration.
@@ -214,7 +214,7 @@
* @see R.styleable#AndroidManifestApplication_localeConfig
*/
@XmlRes
- int getLocaleConfigRes();
+ int getLocaleConfigResourceId();
/**
* @see PackageInfo#getLongVersionCode()
@@ -247,7 +247,7 @@
* @see R.styleable#AndroidManifestApplication_networkSecurityConfig
*/
@XmlRes
- int getNetworkSecurityConfigRes();
+ int getNetworkSecurityConfigResourceId();
/**
* @see PackageInfo#requiredAccountType
@@ -277,7 +277,7 @@
* @see R.styleable#AndroidManifestApplication_roundIcon
*/
@DrawableRes
- int getRoundIconRes();
+ int getRoundIconResourceId();
/**
* @see R.styleable#AndroidManifestSdkLibrary_name
@@ -297,7 +297,7 @@
* @see R.styleable#AndroidManifest_sharedUserLabel
*/
@StringRes
- int getSharedUserLabelRes();
+ int getSharedUserLabelResourceId();
/**
* @return List of all splits for a package. Note that base.apk is considered a
@@ -336,7 +336,7 @@
* @see R.styleable#AndroidManifestApplication_theme
*/
@StyleRes
- int getThemeRes();
+ int getThemeResourceId();
/**
* @see ApplicationInfo#uiOptions
@@ -367,19 +367,19 @@
* @see ApplicationInfo#FLAG_ALLOW_BACKUP
* @see R.styleable#AndroidManifestApplication_allowBackup
*/
- boolean isAllowBackup();
+ boolean isBackupAllowed();
/**
* @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA
* @see R.styleable#AndroidManifestApplication_allowClearUserData
*/
- boolean isAllowClearUserData();
+ boolean isClearUserDataAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
* @see R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore
*/
- boolean isAllowClearUserDataOnFailedRestore();
+ boolean isClearUserDataOnFailedRestoreAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
@@ -391,7 +391,7 @@
* @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING
* @see R.styleable#AndroidManifestApplication_allowTaskReparenting
*/
- boolean isAllowTaskReparenting();
+ boolean isTaskReparentingAllowed();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -424,7 +424,7 @@
* @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE
* @see R.styleable#AndroidManifestApplication_cantSaveState
*/
- boolean isCantSaveState();
+ boolean isSaveStateDisallowed();
/**
* @see PackageInfo#coreApp
@@ -459,7 +459,7 @@
* @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS
* @see R.styleable#AndroidManifestApplication_extractNativeLibs
*/
- boolean isExtractNativeLibs();
+ boolean isExtractNativeLibrariesRequested();
/**
* @see ApplicationInfo#FLAG_FACTORY_TEST
@@ -481,13 +481,13 @@
* @see ApplicationInfo#FLAG_HAS_CODE
* @see R.styleable#AndroidManifestApplication_hasCode
*/
- boolean isHasCode();
+ boolean isDeclaredHavingCode();
/**
* @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
* @see R.styleable#AndroidManifestApplication_hasFragileUserData
*/
- boolean isHasFragileUserData();
+ boolean isUserDataFragile();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
@@ -499,7 +499,7 @@
* @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE
* @see R.styleable#AndroidManifestApplication_killAfterRestore
*/
- boolean isKillAfterRestore();
+ boolean isKillAfterRestoreAllowed();
/**
* @see ApplicationInfo#FLAG_LARGE_HEAP
@@ -596,7 +596,7 @@
* @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
* @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
*/
- boolean isSupportsExtraLargeScreens();
+ boolean isExtraLargeScreensSupported();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -605,7 +605,7 @@
* @see R.styleable#AndroidManifestSupportsScreens_largeScreens
* @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
*/
- boolean isSupportsLargeScreens();
+ boolean isLargeScreensSupported();
/**
* If omitted from manifest, returns true.
@@ -613,13 +613,13 @@
* @see R.styleable#AndroidManifestSupportsScreens_normalScreens
* @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
*/
- boolean isSupportsNormalScreens();
+ boolean isNormalScreensSupported();
/**
* @see ApplicationInfo#FLAG_SUPPORTS_RTL
* @see R.styleable#AndroidManifestApplication_supportsRtl
*/
- boolean isSupportsRtl();
+ boolean isRtlSupported();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -628,7 +628,7 @@
* @see R.styleable#AndroidManifestSupportsScreens_smallScreens
* @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
*/
- boolean isSupportsSmallScreens();
+ boolean isSmallScreensSupported();
/**
* @see ApplicationInfo#FLAG_TEST_ONLY
@@ -643,13 +643,13 @@
*
* @see R.attr#use32bitAbi
*/
- boolean isUse32BitAbi();
+ boolean is32BitAbiPreferred();
/**
* @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC
* @see R.styleable#AndroidManifestApplication_usesCleartextTraffic
*/
- boolean isUsesCleartextTraffic();
+ boolean isCleartextTrafficAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX
@@ -661,7 +661,7 @@
* @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API
* @see R.styleable#AndroidManifestApplication_usesNonSdkApi
*/
- boolean isUsesNonSdkApi();
+ boolean isNonSdkApiRequested();
/**
* @see ApplicationInfo#FLAG_VM_SAFE_MODE
@@ -892,7 +892,7 @@
/**
* If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
- * Otherwise, it's stored as {@link #getLabelRes()}.
+ * Otherwise, it's stored as {@link #getLabelResourceId()}.
*
* @see ApplicationInfo#nonLocalizedLabel
* @see R.styleable#AndroidManifestApplication_label
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 106b149..2c37876 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -160,6 +160,14 @@
/**
* List of shared libraries that this package declares a dependency on. This includes all
* types of libraries, system or app provided and Java or native.
+ * <p/>
+ * This includes libraries declared in the manifest under the following tags:
+ * <ul>
+ * <li>uses-library</li>
+ * <li>uses-native-library</li>
+ * <li>uses-sdk-library</li>
+ * <li>uses-static-library</li>
+ * </ul>
*/
@NonNull
List<SharedLibrary> getSharedLibraryDependencies();
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index b73ff34..ee793c8 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -114,7 +114,7 @@
return input.error(result);
}
- if (receiver && pkg.isCantSaveState()) {
+ if (receiver && pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have receivers in its main process
if (Objects.equals(activity.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have receivers "
@@ -129,7 +129,7 @@
activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0))
.setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions()));
- activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
+ activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isTaskReparentingAllowed(), sa)
| flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
| flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
| flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
index 4cb4dd0..37bed15 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
@@ -136,7 +136,7 @@
sa.recycle();
}
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have providers in its main process
if (Objects.equals(provider.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have providers"
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
index a812257..c15266f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
@@ -115,7 +115,7 @@
sa.recycle();
}
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (Objects.equals(service.getProcessName(), packageName)) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index bb36758..6cb6a97 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -163,19 +163,20 @@
ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
- ParsingPackage setAllowBackup(boolean allowBackup);
+ ParsingPackage setBackupAllowed(boolean allowBackup);
- ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+ ParsingPackage setClearUserDataAllowed(boolean allowClearUserData);
- ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+ ParsingPackage setClearUserDataOnFailedRestoreAllowed(
+ boolean allowClearUserDataOnFailedRestore);
- ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+ ParsingPackage setTaskReparentingAllowed(boolean allowTaskReparenting);
ParsingPackage setResourceOverlay(boolean isResourceOverlay);
ParsingPackage setBackupInForeground(boolean backupInForeground);
- ParsingPackage setCantSaveState(boolean cantSaveState);
+ ParsingPackage setSaveStateDisallowed(boolean cantSaveState);
ParsingPackage setDebuggable(boolean debuggable);
@@ -185,19 +186,19 @@
ParsingPackage setExternalStorage(boolean externalStorage);
- ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+ ParsingPackage setExtractNativeLibrariesRequested(boolean extractNativeLibs);
ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
- ParsingPackage setHasCode(boolean hasCode);
+ ParsingPackage setDeclaredHavingCode(boolean hasCode);
- ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+ ParsingPackage setUserDataFragile(boolean hasFragileUserData);
ParsingPackage setGame(boolean isGame);
ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
- ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+ ParsingPackage setKillAfterRestoreAllowed(boolean killAfterRestore);
ParsingPackage setLargeHeap(boolean largeHeap);
@@ -231,15 +232,15 @@
ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
- ParsingPackage setSupportsRtl(boolean supportsRtl);
+ ParsingPackage setRtlSupported(boolean supportsRtl);
ParsingPackage setTestOnly(boolean testOnly);
ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
- ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+ ParsingPackage setCleartextTrafficAllowed(boolean usesCleartextTraffic);
- ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+ ParsingPackage setNonSdkApiRequested(boolean usesNonSdkApi);
ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
@@ -255,7 +256,7 @@
ParsingPackage setBackupAgentName(String backupAgentName);
- ParsingPackage setBannerRes(int banner);
+ ParsingPackage setBannerResourceId(int banner);
ParsingPackage setCategory(int category);
@@ -265,7 +266,7 @@
ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
- ParsingPackage setDescriptionRes(int descriptionRes);
+ ParsingPackage setDescriptionResourceId(int descriptionRes);
ParsingPackage setEnabled(boolean enabled);
@@ -281,24 +282,24 @@
ParsingPackage setCrossProfile(boolean crossProfile);
- ParsingPackage setFullBackupContentRes(int fullBackupContentRes);
+ ParsingPackage setFullBackupContentResourceId(int fullBackupContentRes);
- ParsingPackage setDataExtractionRulesRes(int dataExtractionRulesRes);
+ ParsingPackage setDataExtractionRulesResourceId(int dataExtractionRulesRes);
ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
- ParsingPackage setIconRes(int iconRes);
+ ParsingPackage setIconResourceId(int iconRes);
ParsingPackage setInstallLocation(int installLocation);
/** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
ParsingPackage setLeavingSharedUser(boolean leavingSharedUser);
- ParsingPackage setLabelRes(int labelRes);
+ ParsingPackage setLabelResourceId(int labelRes);
ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
- ParsingPackage setLogoRes(int logo);
+ ParsingPackage setLogoResourceId(int logo);
ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
@@ -308,7 +309,7 @@
ParsingPackage setMaxSdkVersion(int maxSdkVersion);
- ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+ ParsingPackage setNetworkSecurityConfigResourceId(int networkSecurityConfigRes);
ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
@@ -334,9 +335,9 @@
ParsingPackage setRestrictedAccountType(String restrictedAccountType);
- ParsingPackage setRoundIconRes(int roundIconRes);
+ ParsingPackage setRoundIconResourceId(int roundIconRes);
- ParsingPackage setSharedUserLabelRes(int sharedUserLabelRes);
+ ParsingPackage setSharedUserLabelResourceId(int sharedUserLabelRes);
ParsingPackage setSigningDetails(@NonNull SigningDetails signingDetails);
@@ -344,23 +345,23 @@
ParsingPackage setStaticSharedLibraryVersion(long staticSharedLibraryVersion);
- ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+ ParsingPackage setLargeScreensSupported(int supportsLargeScreens);
- ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+ ParsingPackage setNormalScreensSupported(int supportsNormalScreens);
- ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+ ParsingPackage setSmallScreensSupported(int supportsSmallScreens);
- ParsingPackage setSupportsExtraLargeScreens(int supportsExtraLargeScreens);
+ ParsingPackage setExtraLargeScreensSupported(int supportsExtraLargeScreens);
ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
- ParsingPackage setThemeRes(int theme);
+ ParsingPackage setThemeResourceId(int theme);
ParsingPackage setRequestForegroundServiceExemption(boolean requestForegroundServiceExemption);
ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
- ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+ ParsingPackage set32BitAbiPreferred(boolean use32BitAbi);
ParsingPackage setVolumeUuid(@Nullable String volumeUuid);
@@ -385,7 +386,7 @@
ParsingPackage setResetEnabledSettingsOnAppDataCleared(
boolean resetEnabledSettingsOnAppDataCleared);
- ParsingPackage setLocaleConfigRes(int localeConfigRes);
+ ParsingPackage setLocaleConfigResourceId(int localeConfigRes);
ParsingPackage setAllowUpdateOwnership(boolean value);
@@ -508,15 +509,15 @@
@Nullable
String getZygotePreloadName();
- boolean isAllowBackup();
+ boolean isBackupAllowed();
- boolean isAllowTaskReparenting();
+ boolean isTaskReparentingAllowed();
boolean isAnyDensity();
boolean isHardwareAccelerated();
- boolean isCantSaveState();
+ boolean isSaveStateDisallowed();
boolean isProfileable();
@@ -528,11 +529,11 @@
boolean isStaticSharedLibrary();
- boolean isSupportsExtraLargeScreens();
+ boolean isExtraLargeScreensSupported();
- boolean isSupportsLargeScreens();
+ boolean isLargeScreensSupported();
- boolean isSupportsNormalScreens();
+ boolean isNormalScreensSupported();
- boolean isSupportsSmallScreens();
+ boolean isSmallScreensSupported();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 31f291f..fda44e4 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -430,7 +430,7 @@
}
}
- pkg.setUse32BitAbi(lite.isUse32bitAbi());
+ pkg.set32BitAbiPreferred(lite.isUse32bitAbi());
return input.success(pkg);
} catch (IllegalArgumentException e) {
return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
@@ -466,7 +466,7 @@
}
return input.success(result.getResult()
- .setUse32BitAbi(lite.isUse32bitAbi()));
+ .set32BitAbiPreferred(lite.isUse32bitAbi()));
} catch (IOException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
@@ -957,10 +957,10 @@
// cannot be windowed / resized. Note that an SDK version of 0 is common for
// pre-Doughnut applications.
if (pkg.getTargetSdkVersion() < DONUT
- || (!pkg.isSupportsSmallScreens()
- && !pkg.isSupportsNormalScreens()
- && !pkg.isSupportsLargeScreens()
- && !pkg.isSupportsExtraLargeScreens()
+ || (!pkg.isSmallScreensSupported()
+ && !pkg.isNormalScreensSupported()
+ && !pkg.isLargeScreensSupported()
+ && !pkg.isExtraLargeScreensSupported()
&& !pkg.isResizeable()
&& !pkg.isAnyDensity())) {
adjustPackageToBeUnresizeableAndUnpipable(pkg);
@@ -1052,7 +1052,8 @@
return input.success(pkg
.setLeavingSharedUser(leaving)
.setSharedUserId(str.intern())
- .setSharedUserLabelRes(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
+ .setSharedUserLabelResourceId(
+ resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
}
private static ParseResult<ParsingPackage> parseKeySets(ParseInput input,
@@ -1885,7 +1886,7 @@
TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
if (labelValue != null) {
- pkg.setLabelRes(labelValue.resourceId);
+ pkg.setLabelResourceId(labelValue.resourceId);
if (labelValue.resourceId == 0) {
pkg.setNonLocalizedLabel(labelValue.coerceToString());
}
@@ -1906,7 +1907,7 @@
pkg.setManageSpaceActivityName(manageSpaceActivityName);
}
- if (pkg.isAllowBackup()) {
+ if (pkg.isBackupAllowed()) {
// backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
// and restoreAnyVersion are only relevant if backup is possible for the
// given application.
@@ -1924,7 +1925,7 @@
}
pkg.setBackupAgentName(backupAgentName)
- .setKillAfterRestore(bool(true,
+ .setKillAfterRestoreAllowed(bool(true,
R.styleable.AndroidManifestApplication_killAfterRestore, sa))
.setRestoreAnyVersion(bool(false,
R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
@@ -1950,7 +1951,7 @@
fullBackupContent = v.data == 0 ? -1 : 0;
}
- pkg.setFullBackupContentRes(fullBackupContent);
+ pkg.setFullBackupContentResourceId(fullBackupContent);
}
if (DEBUG_BACKUP) {
Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
@@ -2024,7 +2025,7 @@
String processName = processNameResult.getResult();
pkg.setProcessName(processName);
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not be in a custom process.
// We can do direct compare because we intern all strings.
if (processName != null && !processName.equals(pkgName)) {
@@ -2224,31 +2225,31 @@
// CHECKSTYLE:off
pkg
// Default true
- .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
- .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
- .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
+ .setBackupAllowed(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
+ .setClearUserDataAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
+ .setClearUserDataOnFailedRestoreAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
.setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
.setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
- .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
- .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
+ .setExtractNativeLibrariesRequested(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
+ .setDeclaredHavingCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
// Default false
- .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
- .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
+ .setTaskReparentingAllowed(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
+ .setSaveStateDisallowed(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
.setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa))
.setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
.setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
.setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
.setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa))
.setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa))
- .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
+ .setUserDataFragile(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
.setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa))
.setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa))
.setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa))
.setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa))
- .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
+ .setRtlSupported(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
.setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa))
.setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
- .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
+ .setNonSdkApiRequested(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
.setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
.setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
.setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
@@ -2260,7 +2261,7 @@
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
.setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
- .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+ .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
// Ints Default 0
.setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
// Ints
@@ -2269,16 +2270,16 @@
.setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa))
.setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa))
// Resource ID
- .setBannerRes(resId(R.styleable.AndroidManifestApplication_banner, sa))
- .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
- .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))
- .setLogoRes(resId(R.styleable.AndroidManifestApplication_logo, sa))
- .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
- .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
- .setThemeRes(resId(R.styleable.AndroidManifestApplication_theme, sa))
- .setDataExtractionRulesRes(
+ .setBannerResourceId(resId(R.styleable.AndroidManifestApplication_banner, sa))
+ .setDescriptionResourceId(resId(R.styleable.AndroidManifestApplication_description, sa))
+ .setIconResourceId(resId(R.styleable.AndroidManifestApplication_icon, sa))
+ .setLogoResourceId(resId(R.styleable.AndroidManifestApplication_logo, sa))
+ .setNetworkSecurityConfigResourceId(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
+ .setRoundIconResourceId(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
+ .setThemeResourceId(resId(R.styleable.AndroidManifestApplication_theme, sa))
+ .setDataExtractionRulesResourceId(
resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
- .setLocaleConfigRes(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
+ .setLocaleConfigResourceId(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
// Strings
.setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
.setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
@@ -2883,13 +2884,13 @@
// This is a trick to get a boolean and still able to detect
// if a value was actually set.
return input.success(pkg
- .setSupportsSmallScreens(
+ .setSmallScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa))
- .setSupportsNormalScreens(
+ .setNormalScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa))
- .setSupportsLargeScreens(
+ .setLargeScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa))
- .setSupportsExtraLargeScreens(
+ .setExtraLargeScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa))
.setResizeable(
anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa))
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 0dc5f76..f248a02 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -19,7 +19,6 @@
import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
@@ -692,8 +691,7 @@
final Intent intent = new Intent(
PowerManager.ACTION_LOW_POWER_STANDBY_POLICY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- Manifest.permission.MANAGE_LOW_POWER_STANDBY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
private void onStandbyTimeoutExpired() {
@@ -812,7 +810,7 @@
}
}
- @NonNull
+ @Nullable
LowPowerStandbyPolicy getPolicy() {
synchronized (mLock) {
if (!mSupportedConfig) {
@@ -914,20 +912,22 @@
final int[] allowlistUids = getAllowlistUidsLocked();
ipw.print("Allowed UIDs=");
ipw.println(Arrays.toString(allowlistUids));
- ipw.println();
final LowPowerStandbyPolicy policy = getPolicy();
- ipw.println("mPolicy:");
- ipw.increaseIndent();
- ipw.print("mIdentifier=");
- ipw.println(policy.getIdentifier());
- ipw.print("mExemptPackages=");
- ipw.println(String.join(",", policy.getExemptPackages()));
- ipw.print("mAllowedReasons=");
- ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons()));
- ipw.print("mAllowedFeatures=");
- ipw.println(String.join(",", policy.getAllowedFeatures()));
- ipw.decreaseIndent();
+ if (policy != null) {
+ ipw.println();
+ ipw.println("mPolicy:");
+ ipw.increaseIndent();
+ ipw.print("mIdentifier=");
+ ipw.println(policy.getIdentifier());
+ ipw.print("mExemptPackages=");
+ ipw.println(String.join(",", policy.getExemptPackages()));
+ ipw.print("mAllowedReasons=");
+ ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons()));
+ ipw.print("mAllowedFeatures=");
+ ipw.println(String.join(",", policy.getAllowedFeatures()));
+ ipw.decreaseIndent();
+ }
ipw.println();
ipw.println("UID allowed reasons:");
@@ -967,17 +967,19 @@
proto.write(LowPowerStandbyControllerDumpProto.ALLOWLIST, appId);
}
- long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY);
final LowPowerStandbyPolicy policy = getPolicy();
- proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier());
- for (String exemptPackage : policy.getExemptPackages()) {
- proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage);
+ if (policy != null) {
+ long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY);
+ proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier());
+ for (String exemptPackage : policy.getExemptPackages()) {
+ proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage);
+ }
+ proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons());
+ for (String feature : policy.getAllowedFeatures()) {
+ proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature);
+ }
+ proto.end(policyToken);
}
- proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons());
- for (String feature : policy.getAllowedFeatures()) {
- proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature);
- }
- proto.end(policyToken);
proto.end(token);
}
}
@@ -1047,6 +1049,9 @@
"Adding to allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
}
synchronized (mLock) {
+ if (!mSupportedConfig) {
+ return;
+ }
if (allowedReason != 0 && !hasAllowedReasonLocked(uid, allowedReason)) {
addAllowedReasonLocked(uid, allowedReason);
if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
@@ -1062,6 +1067,9 @@
Slog.i(TAG, "Removing from allowlist: uid=" + uid + ", allowedReason=" + allowedReason);
}
synchronized (mLock) {
+ if (!mSupportedConfig) {
+ return;
+ }
if (allowedReason != 0 && hasAllowedReasonLocked(uid, allowedReason)) {
removeAllowedReasonLocked(uid, allowedReason);
if ((getPolicy().getAllowedReasons() & allowedReason) != 0) {
@@ -1077,6 +1085,9 @@
final PackageManager packageManager = mContext.getPackageManager();
final LowPowerStandbyPolicy policy = getPolicy();
final List<Integer> appIds = new ArrayList<>();
+ if (policy == null) {
+ return appIds;
+ }
for (String packageName : policy.getExemptPackages()) {
try {
@@ -1100,6 +1111,9 @@
final List<UserHandle> userHandles = userManager.getUserHandles(true);
final ArraySet<Integer> uids = new ArraySet<>(mUidAllowedReasons.size());
final LowPowerStandbyPolicy policy = getPolicy();
+ if (policy == null) {
+ return new int[0];
+ }
final int policyAllowedReasons = policy.getAllowedReasons();
for (int i = 0; i < mUidAllowedReasons.size(); i++) {
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index e148a48..4839c96 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -233,7 +233,9 @@
void checkRecognitionSupport(
Intent recognizerIntent,
+ AttributionSource attributionSource,
IRecognitionSupportCallback callback) {
+
if (!mConnected) {
try {
callback.onError(SpeechRecognizer.ERROR_SERVER_DISCONNECTED);
@@ -243,15 +245,16 @@
}
return;
}
- run(service -> service.checkRecognitionSupport(recognizerIntent, callback));
+ run(service ->
+ service.checkRecognitionSupport(recognizerIntent, attributionSource, callback));
}
- void triggerModelDownload(Intent recognizerIntent) {
+ void triggerModelDownload(Intent recognizerIntent, AttributionSource attributionSource) {
if (!mConnected) {
Slog.e(TAG, "#downloadModel failed due to connection.");
return;
}
- run(service -> service.triggerModelDownload(recognizerIntent));
+ run(service -> service.triggerModelDownload(recognizerIntent, attributionSource));
}
void shutdown(IBinder clientToken) {
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index e245c08..6aa600a 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -183,13 +183,17 @@
@Override
public void checkRecognitionSupport(
Intent recognizerIntent,
+ AttributionSource attributionSource,
IRecognitionSupportCallback callback) {
- service.checkRecognitionSupport(recognizerIntent, callback);
+ service.checkRecognitionSupport(
+ recognizerIntent, attributionSource, callback);
}
@Override
- public void triggerModelDownload(Intent recognizerIntent) {
- service.triggerModelDownload(recognizerIntent);
+ public void triggerModelDownload(
+ Intent recognizerIntent,
+ AttributionSource attributionSource) {
+ service.triggerModelDownload(recognizerIntent, attributionSource);
}
});
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 5801920..fc960d8 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -129,4 +129,9 @@
public void dumpDebugLog(@NonNull PrintWriter printWriter) {
SystemClockTime.dump(printWriter);
}
+
+ @Override
+ public void runAsync(@NonNull Runnable runnable) {
+ mHandler.post(runnable);
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
index 5df5cbc..4b65c55 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternal.java
@@ -17,10 +17,13 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.ManualTimeSuggestion;
+import com.android.server.timezonedetector.StateChangeListener;
+
/**
* The internal (in-process) system server API for the time detector service.
*
@@ -61,11 +64,26 @@
/**
* Suggests a network time to the time detector. The suggestion may not be used by the time
* detector to set the device's time depending on device configuration and user settings, but
- * can replace previous network suggestions received.
+ * can replace previous network suggestions received. See also
+ * {@link #addNetworkTimeUpdateListener(StateChangeListener)} and
+ * {@link #getLatestNetworkSuggestion()}.
*/
void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
/**
+ * Adds a listener that will be notified when a new network time is available. See {@link
+ * #getLatestNetworkSuggestion()}.
+ */
+ void addNetworkTimeUpdateListener(
+ @NonNull StateChangeListener networkSuggestionUpdateListener);
+
+ /**
+ * Returns the latest / best network time received by the time detector.
+ */
+ @Nullable
+ NetworkTimeSuggestion getLatestNetworkSuggestion();
+
+ /**
* Suggests a GNSS-derived time to the time detector. The suggestion may not be used by the time
* detector to set the device's time depending on device configuration and user settings, but
* can replace previous GNSS suggestions received.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
index af168f8..7e96a43 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorInternalImpl.java
@@ -24,6 +24,7 @@
import android.os.Handler;
import com.android.server.timezonedetector.CurrentUserIdentityInjector;
+import com.android.server.timezonedetector.StateChangeListener;
import java.util.Objects;
@@ -87,6 +88,19 @@
}
@Override
+ public void addNetworkTimeUpdateListener(
+ @NonNull StateChangeListener networkTimeUpdateListener) {
+ Objects.requireNonNull(networkTimeUpdateListener);
+ mTimeDetectorStrategy.addNetworkTimeUpdateListener(networkTimeUpdateListener);
+ }
+
+ @Override
+ @NonNull
+ public NetworkTimeSuggestion getLatestNetworkSuggestion() {
+ return mTimeDetectorStrategy.getLatestNetworkSuggestion();
+ }
+
+ @Override
public void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion) {
Objects.requireNonNull(suggestion);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index a9dcff4..0da967a 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -47,6 +47,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper;
import com.android.server.timezonedetector.CallerIdentityInjector;
import com.android.server.timezonedetector.CurrentUserIdentityInjector;
@@ -405,13 +406,19 @@
// TODO(b/222295093): Return the latest network time from mTimeDetectorStrategy once we can
// be sure that all uses of NtpTrustedTime results in a suggestion being made to the time
// detector. mNtpTrustedTime can be removed once this happens.
- NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
- if (ntpResult != null) {
- UnixEpochTime unixEpochTime = new UnixEpochTime(
- ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
- return new NetworkTimeSuggestion(unixEpochTime, ntpResult.getUncertaintyMillis());
+ if (TimeDetectorNetworkTimeHelper.isInUse()) {
+ // The new implementation.
+ return mTimeDetectorStrategy.getLatestNetworkSuggestion();
} else {
- return null;
+ // The old implementation.
+ NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult();
+ if (ntpResult != null) {
+ UnixEpochTime unixEpochTime = new UnixEpochTime(
+ ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
+ return new NetworkTimeSuggestion(unixEpochTime, ntpResult.getUncertaintyMillis());
+ } else {
+ return null;
+ }
}
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index dbd7172..11cec66 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -29,6 +29,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.timezonedetector.Dumpable;
+import com.android.server.timezonedetector.StateChangeListener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -104,11 +105,19 @@
/**
* Processes the suggested network time. The suggestion may not be used to set the device's time
* depending on device configuration and user settings, but can replace previous network
- * suggestions received.
+ * suggestions received. See also
+ * {@link #addNetworkTimeUpdateListener(StateChangeListener)} and
+ * {@link #getLatestNetworkSuggestion()}.
*/
void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
/**
+ * Adds a listener that will be notified when a new network time is available. See {@link
+ * #getLatestNetworkSuggestion()}.
+ */
+ void addNetworkTimeUpdateListener(@NonNull StateChangeListener networkSuggestionUpdateListener);
+
+ /**
* Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
* one.
*/
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index d679bbe..b293bac 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -36,6 +36,7 @@
import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.os.Handler;
+import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -125,6 +126,9 @@
private final ReferenceWithHistory<ExternalTimeSuggestion> mLastExternalSuggestion =
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+ @GuardedBy("this")
+ private final ArraySet<StateChangeListener> mNetworkTimeUpdateListeners = new ArraySet<>();
+
/**
* Used by {@link TimeDetectorStrategyImpl} to interact with device configuration / settings
* / system properties. It can be faked for testing.
@@ -180,6 +184,11 @@
* Dumps the time debug log to the supplied {@link PrintWriter}.
*/
void dumpDebugLog(PrintWriter printWriter);
+
+ /**
+ * Requests that the supplied runnable is invoked asynchronously.
+ */
+ void runAsync(@NonNull Runnable runnable);
}
static TimeDetectorStrategy create(
@@ -307,6 +316,7 @@
NetworkTimeSuggestion lastNetworkSuggestion = mLastNetworkSuggestion.get();
if (lastNetworkSuggestion == null || !lastNetworkSuggestion.equals(suggestion)) {
mLastNetworkSuggestion.set(suggestion);
+ notifyNetworkTimeUpdateListenersAsynchronously();
}
// Now perform auto time detection. The new suggestion may be used to modify the system
@@ -315,6 +325,20 @@
doAutoTimeDetection(reason);
}
+ @GuardedBy("this")
+ private void notifyNetworkTimeUpdateListenersAsynchronously() {
+ for (StateChangeListener listener : mNetworkTimeUpdateListeners) {
+ // This is queuing asynchronous notification, so no need to surrender the "this" lock.
+ mEnvironment.runAsync(listener::onChange);
+ }
+ }
+
+ @Override
+ public synchronized void addNetworkTimeUpdateListener(
+ @NonNull StateChangeListener networkSuggestionUpdateListener) {
+ mNetworkTimeUpdateListeners.add(networkSuggestionUpdateListener);
+ }
+
@Override
@Nullable
public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
@@ -325,6 +349,8 @@
public synchronized void clearLatestNetworkSuggestion() {
mLastNetworkSuggestion.set(null);
+ notifyNetworkTimeUpdateListenersAsynchronously();
+
// The loss of network time may change the time signal to use to set the system clock.
String reason = "Network time cleared";
doAutoTimeDetection(reason);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index f829449..61c137e 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -1140,7 +1140,8 @@
@Override
- public void notifyRecordingStarted(IBinder sessionToken, String recordingId, int userId) {
+ public void notifyRecordingStarted(IBinder sessionToken, String recordingId,
+ String requestId, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
@@ -1151,7 +1152,8 @@
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
- getSessionLocked(sessionState).notifyRecordingStarted(recordingId);
+ getSessionLocked(sessionState).notifyRecordingStarted(
+ recordingId, requestId);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in notifyRecordingStarted", e);
}
@@ -2831,7 +2833,7 @@
}
@Override
- public void onRequestStartRecording(Uri programUri) {
+ public void onRequestStartRecording(String requestId, Uri programUri) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestStartRecording: " + programUri);
@@ -2840,7 +2842,8 @@
return;
}
try {
- mSessionState.mClient.onRequestStartRecording(programUri, mSessionState.mSeq);
+ mSessionState.mClient.onRequestStartRecording(
+ requestId, programUri, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestStartRecording", e);
}
@@ -2866,7 +2869,7 @@
@Override
public void onRequestScheduleRecording(
- String inputId, Uri channelUri, Uri programUri, Bundle params) {
+ String requestId, String inputId, Uri channelUri, Uri programUri, Bundle params) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestScheduleRecording");
@@ -2876,7 +2879,7 @@
}
try {
mSessionState.mClient.onRequestScheduleRecording(
- inputId, channelUri, programUri, params, mSessionState.mSeq);
+ requestId, inputId, channelUri, programUri, params, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestScheduleRecording", e);
}
@@ -2884,8 +2887,8 @@
}
@Override
- public void onRequestScheduleRecording2(String inputId, Uri channelUri, long start,
- long duration, int repeat, Bundle params) {
+ public void onRequestScheduleRecording2(String inputId, String requestId, Uri channelUri,
+ long start, long duration, int repeat, Bundle params) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestScheduleRecording2");
@@ -2894,8 +2897,8 @@
return;
}
try {
- mSessionState.mClient.onRequestScheduleRecording2(inputId, channelUri, start,
- duration, repeat, params, mSessionState.mSeq);
+ mSessionState.mClient.onRequestScheduleRecording2(requestId, inputId,
+ channelUri, start, duration, repeat, params, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestScheduleRecording2", e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 502bfd1..7a95987 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1382,6 +1382,31 @@
}
@Override
+ public void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
+ int backgroundColor) {
+ final long origId = Binder.clearCallingIdentity();
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
+ if (r != null) {
+ r.overrideCustomTransition(open, enterAnim, exitAnim, backgroundColor);
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ @Override
+ public void clearOverrideActivityTransition(IBinder token, boolean open) {
+ final long origId = Binder.clearCallingIdentity();
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
+ if (r != null) {
+ r.clearCustomTransition(open);
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ @Override
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim, @ColorInt int backgroundColor) {
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index ff1d442..d844c6f 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -266,7 +266,7 @@
* @param resolvedType the resolved type.
*/
@NonNull
- public Builder setResolvedType(@NonNull String resolvedType) {
+ public Builder setResolvedType(@Nullable String resolvedType) {
mResolvedType = resolvedType;
return this;
}
@@ -276,7 +276,7 @@
* @param callingPackage the calling package.
*/
@NonNull
- public Builder setCallingPackage(@NonNull String callingPackage) {
+ public Builder setCallingPackage(@Nullable String callingPackage) {
mCallingPackage = callingPackage;
return this;
}
@@ -286,7 +286,7 @@
* @param callingFeatureId the calling feature id.
*/
@NonNull
- public Builder setCallingFeatureId(@NonNull String callingFeatureId) {
+ public Builder setCallingFeatureId(@Nullable String callingFeatureId) {
mCallingFeatureId = callingFeatureId;
return this;
}
@@ -296,7 +296,7 @@
* @param checkedOptions the {@link ActivityOptions}.
*/
@NonNull
- public Builder setCheckedOptions(@NonNull ActivityOptions checkedOptions) {
+ public Builder setCheckedOptions(@Nullable ActivityOptions checkedOptions) {
mCheckedOptions = checkedOptions;
return this;
}
@@ -306,7 +306,7 @@
* @param clearOptionsAnimationRunnable the calling package.
*/
@NonNull
- public Builder setClearOptionsAnimationRunnable(@NonNull
+ public Builder setClearOptionsAnimationRunnable(@Nullable
Runnable clearOptionsAnimationRunnable) {
mClearOptionsAnimation = clearOptionsAnimationRunnable;
return this;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 81ee9cd..828848b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -945,6 +945,10 @@
// Whether the ActivityEmbedding is enabled on the app.
private final boolean mAppActivityEmbeddingSplitsEnabled;
+ // Records whether client has overridden the WindowAnimation_(Open/Close)(Enter/Exit)Animation.
+ private CustomAppTransition mCustomOpenTransition;
+ private CustomAppTransition mCustomCloseTransition;
+
private final Runnable mPauseTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -10352,6 +10356,41 @@
&& !inPinnedWindowingMode() && !inFreeformWindowingMode();
}
+ void overrideCustomTransition(boolean open, int enterAnim, int exitAnim, int backgroundColor) {
+ CustomAppTransition transition = getCustomAnimation(open);
+ if (transition == null) {
+ transition = new CustomAppTransition();
+ if (open) {
+ mCustomOpenTransition = transition;
+ } else {
+ mCustomCloseTransition = transition;
+ }
+ }
+
+ transition.mEnterAnim = enterAnim;
+ transition.mExitAnim = exitAnim;
+ transition.mBackgroundColor = backgroundColor;
+ }
+
+ void clearCustomTransition(boolean open) {
+ if (open) {
+ mCustomOpenTransition = null;
+ } else {
+ mCustomCloseTransition = null;
+ }
+ }
+
+ CustomAppTransition getCustomAnimation(boolean open) {
+ return open ? mCustomOpenTransition : mCustomCloseTransition;
+ }
+
+ // Override the WindowAnimation_(Open/Close)(Enter/Exit)Animation
+ static class CustomAppTransition {
+ int mEnterAnim;
+ int mExitAnim;
+ int mBackgroundColor;
+ }
+
static class Builder {
private final ActivityTaskManagerService mAtmService;
private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c37a3d7..9ca2015 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1967,7 +1967,7 @@
FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
/* caller_uid */
- mSourceRecord != null ? mSourceRecord.getUid() : -1,
+ mSourceRecord != null ? mSourceRecord.getUid() : mCallingUid,
/* caller_activity_class_name */
mSourceRecord != null ? mSourceRecord.info.name : null,
/* target_task_top_activity_uid */
@@ -1988,10 +1988,12 @@
/* action */
action,
/* version */
- 2,
+ 3,
/* multi_window - we have our source not in the target task, but both are visible */
targetTask != null && mSourceRecord != null
- && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible()
+ && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible(),
+ /* bal_code */
+ mBalCode
);
boolean shouldBlockActivityStart =
@@ -1999,19 +2001,20 @@
if (ActivitySecurityModelFeatureFlags.shouldShowToast(mCallingUid)) {
UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
- (shouldBlockActivityStart
- ? "Activity start blocked by "
- : "Activity start would be blocked by ")
- + ActivitySecurityModelFeatureFlags.DOC_LINK,
+ "Activity start from " + r.launchedFromPackage
+ + (shouldBlockActivityStart ? " " : " would be ")
+ + "blocked by " + ActivitySecurityModelFeatureFlags.DOC_LINK,
Toast.LENGTH_SHORT).show());
}
if (shouldBlockActivityStart) {
Slog.e(TAG, "Abort Launching r: " + r
- + " as source: " + mSourceRecord
- + "is in background. New task: " + newTask
- + ". Top activity: " + targetTopActivity);
+ + " as source: "
+ + (mSourceRecord != null ? mSourceRecord : r.launchedFromPackage)
+ + " is in background. New task: " + newTask
+ + ". Top activity: " + targetTopActivity
+ + ". BAL Code: " + mBalCode);
return false;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 2869133..3876290 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1667,9 +1667,11 @@
/* action */
FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__FINISH_TASK,
/* version */
- 1,
+ 3,
/* multi_window */
- false
+ false,
+ /* bal_code */
+ -1
);
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index b9a4ed8..f73c68a 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -142,6 +142,7 @@
import com.android.internal.util.DumpUtils.Dump;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
+import com.android.server.wm.ActivityRecord.CustomAppTransition;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -886,9 +887,18 @@
a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
} else {
int animAttr = mapOpenCloseTransitTypes(transit, enter);
- a = animAttr == 0 ? null : (canCustomizeAppTransition
- ? loadAnimationAttr(lp, animAttr, transit)
- : mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit));
+ if (animAttr != 0) {
+ a = loadCustomActivityAnimation(animAttr, enter, container);
+ if (a == null) {
+ if (canCustomizeAppTransition) {
+ a = loadAnimationAttr(lp, animAttr, transit);
+ } else {
+ a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit);
+ }
+ }
+ } else {
+ a = null;
+ }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
@@ -901,6 +911,48 @@
return a;
}
+ Animation loadCustomActivityAnimation(int animAttr, boolean enter, WindowContainer container) {
+ ActivityRecord customAnimationSource = container.asActivityRecord();
+ if (customAnimationSource == null) {
+ return null;
+ }
+
+ // Only top activity can customize activity animation.
+ // If the animation is for the one below, try to get from the above activity.
+ if (animAttr == WindowAnimation_activityOpenExitAnimation
+ || animAttr == WindowAnimation_activityCloseEnterAnimation) {
+ customAnimationSource = customAnimationSource.getTask()
+ .getActivityAbove(customAnimationSource);
+ if (customAnimationSource == null) {
+ return null;
+ }
+ }
+ final CustomAppTransition custom;
+ switch (animAttr) {
+ case WindowAnimation_activityOpenEnterAnimation:
+ case WindowAnimation_activityOpenExitAnimation:
+ custom = customAnimationSource.getCustomAnimation(true /* open */);
+ break;
+ case WindowAnimation_activityCloseEnterAnimation:
+ case WindowAnimation_activityCloseExitAnimation:
+ custom = customAnimationSource.getCustomAnimation(false /* open */);
+ break;
+ default:
+ return null;
+ }
+ if (custom != null) {
+ final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
+ customAnimationSource.packageName, enter
+ ? custom.mEnterAnim : custom.mExitAnim);
+ if (a != null && custom.mBackgroundColor != 0) {
+ a.setBackdropColor(custom.mBackgroundColor);
+ a.setShowBackdrop(true);
+ }
+ return a;
+ }
+ return null;
+ }
+
int getAppRootTaskClipMode() {
return mNextAppTransitionRequests.contains(TRANSIT_RELAUNCH)
|| mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY)
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 63dc7d2..f94fd2b 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -102,6 +102,41 @@
boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
long lastStopAppSwitchesTime, long lastActivityLaunchTime,
long lastActivityFinishTime) {
+ // Allow if the proc is instrumenting with background activity starts privs.
+ if (hasBackgroundActivityStartPrivileges) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[Process(" + pid
+ + ")] Activity start allowed: process instrumenting with background "
+ + "activity starts privileges");
+ }
+ return BAL_ALLOW_BAL_PERMISSION;
+ }
+ // Allow if the flag was explicitly set.
+ if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[Process(" + pid
+ + ")] Activity start allowed: process allowed by token");
+ }
+ return BAL_ALLOW_BAL_PERMISSION;
+ }
+ // Allow if the caller is bound by a UID that's currently foreground.
+ if (isBoundByForegroundUid()) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[Process(" + pid
+ + ")] Activity start allowed: process bound by foreground uid");
+ }
+ return BAL_ALLOW_VISIBLE_WINDOW;
+ }
+ // Allow if the caller has an activity in any foreground task.
+ if (hasActivityInVisibleTask
+ && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[Process(" + pid
+ + ")] Activity start allowed: process has activity in foreground task");
+ }
+ return BAL_ALLOW_FOREGROUND;
+ }
+
// If app switching is not allowed, we ignore all the start activity grace period
// exception so apps cannot start itself in onPause() after pressing home button.
if (appSwitchState == APP_SWITCH_ALLOW) {
@@ -129,40 +164,6 @@
}
}
- // Allow if the proc is instrumenting with background activity starts privs.
- if (hasBackgroundActivityStartPrivileges) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process instrumenting with background "
- + "activity starts privileges");
- }
- return BAL_ALLOW_BAL_PERMISSION;
- }
- // Allow if the caller has an activity in any foreground task.
- if (hasActivityInVisibleTask
- && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process has activity in foreground task");
- }
- return BAL_ALLOW_FOREGROUND;
- }
- // Allow if the caller is bound by a UID that's currently foreground.
- if (isBoundByForegroundUid()) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process bound by foreground uid");
- }
- return BAL_ALLOW_VISIBLE_WINDOW;
- }
- // Allow if the flag was explicitly set.
- if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[Process(" + pid
- + ")] Activity start allowed: process allowed by token");
- }
- return BAL_ALLOW_BAL_PERMISSION;
- }
return BAL_BLOCK;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fe9306b..626bac4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1014,6 +1014,9 @@
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing
|= w.mAttrs.preferMinimalPostProcessing;
+ mTmpApplySurfaceChangesTransactionState.disableHdrConversion
+ |= !(w.mAttrs.isHdrConversionEnabled());
+
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
@@ -4891,6 +4894,7 @@
mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
+ mTmpApplySurfaceChangesTransactionState.disableHdrConversion,
true /* inTraversal, must call performTraversalInTrans... below */);
}
// If the display now has content, or no longer has content, update recording.
@@ -5095,6 +5099,7 @@
public int preferredModeId;
public float preferredMinRefreshRate;
public float preferredMaxRefreshRate;
+ public boolean disableHdrConversion;
void reset() {
displayHasContent = false;
@@ -5105,6 +5110,7 @@
preferredModeId = 0;
preferredMinRefreshRate = 0;
preferredMaxRefreshRate = 0;
+ disableHdrConversion = false;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 294e90b..c2afeaf 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -904,37 +904,46 @@
* starting (about to be visible) activity that is fullscreen (opaque).
* @param starting The currently starting activity or null if there is none.
*/
- @VisibleForTesting
- boolean isTranslucent(ActivityRecord starting) {
+ boolean isTranslucent(@Nullable ActivityRecord starting) {
if (!isAttached() || isForceHidden() || isForceTranslucent()) {
return true;
}
final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
- PooledLambda.__(ActivityRecord.class), starting);
+ PooledLambda.__(ActivityRecord.class), starting, false /* including*/);
final ActivityRecord opaque = getActivity(p);
p.recycle();
return opaque == null;
}
- private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
- if (r.finishing) {
- // We don't factor in finishing activities when determining translucency since
- // they will be gone soon.
- return false;
+ /**
+ * Whether the TaskFragment should be treated as translucent for the current transition.
+ * This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks
+ * finishing activities when the TaskFragment itself is becoming invisible.
+ */
+ boolean isTranslucentForTransition() {
+ if (!isAttached() || isForceHidden() || isForceTranslucent()) {
+ return true;
}
+ // Including finishing Activity if the TaskFragment is becoming invisible in the transition.
+ final boolean includingFinishing = !isVisibleRequested();
+ final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
+ PooledLambda.__(ActivityRecord.class), null /* starting */, includingFinishing);
+ final ActivityRecord opaque = getActivity(p);
+ p.recycle();
+ return opaque == null;
+ }
+ private static boolean isOpaqueActivity(@NonNull ActivityRecord r,
+ @Nullable ActivityRecord starting, boolean includingFinishing) {
if (!r.visibleIgnoringKeyguard && r != starting) {
// Also ignore invisible activities that are not the currently starting
// activity (about to be visible).
return false;
}
- if (r.occludesParent()) {
- // Root task isn't translucent if it has at least one fullscreen activity
- // that is visible.
- return true;
- }
- return false;
+ // TaskFragment isn't translucent if it has at least one fullscreen activity that is
+ // visible.
+ return r.occludesParent(includingFinishing);
}
ActivityRecord getTopNonFinishingActivity() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d23b954..216544a 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1447,22 +1447,25 @@
private static boolean isTranslucent(@NonNull WindowContainer wc) {
final TaskFragment taskFragment = wc.asTaskFragment();
- if (taskFragment != null) {
- if (taskFragment.isTranslucent(null /* starting */)) {
- return true;
- }
- final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
- if (adjacentTaskFragment != null) {
- // Treat the TaskFragment as translucent if its adjacent TF is, otherwise everything
- // behind two adjacent TaskFragments are occluded.
- return adjacentTaskFragment.isTranslucent(null /* starting */);
- }
+ if (taskFragment == null) {
+ return !wc.fillsParent();
}
- // TODO(b/172695805): hierarchical check. This is non-trivial because for containers
- // it is effected by child visibility but needs to work even
- // before visibility is committed. This means refactoring some
- // checks to use requested visibility.
- return !wc.fillsParent();
+
+ // Check containers differently as they are affected by child visibility.
+
+ if (taskFragment.isTranslucentForTransition()) {
+ // TaskFragment doesn't contain occluded ActivityRecord.
+ return true;
+ }
+ final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ if (adjacentTaskFragment != null) {
+ // When the TaskFragment has an adjacent TaskFragment, sibling behind them should be
+ // hidden unless any of them are translucent.
+ return adjacentTaskFragment.isTranslucentForTransition();
+ } else {
+ // Non-filling without adjacent is considered as translucent.
+ return !wc.fillsParent();
+ }
}
/**
@@ -1878,6 +1881,12 @@
out.addChange(change);
}
+ TransitionInfo.AnimationOptions animOptions = null;
+ if (topApp.asActivityRecord() != null) {
+ final ActivityRecord topActivity = topApp.asActivityRecord();
+ animOptions = addCustomActivityTransition(topActivity, true/* open */, null);
+ animOptions = addCustomActivityTransition(topActivity, false/* open */, animOptions);
+ }
final WindowManager.LayoutParams animLp =
getLayoutParamsForAnimationsStyle(type, sortedTargets);
if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
@@ -1885,14 +1894,33 @@
// Don't send animation options if no windowAnimations have been set or if the we are
// running an app starting animation, in which case we don't want the app to be able to
// change its animation directly.
- TransitionInfo.AnimationOptions animOptions =
- TransitionInfo.AnimationOptions.makeAnimOptionsFromLayoutParameters(animLp);
+ if (animOptions != null) {
+ animOptions.addOptionsFromLayoutParameters(animLp);
+ } else {
+ animOptions = TransitionInfo.AnimationOptions
+ .makeAnimOptionsFromLayoutParameters(animLp);
+ }
+ }
+ if (animOptions != null) {
out.setAnimationOptions(animOptions);
}
-
return out;
}
+ static TransitionInfo.AnimationOptions addCustomActivityTransition(ActivityRecord topActivity,
+ boolean open, TransitionInfo.AnimationOptions animOptions) {
+ final ActivityRecord.CustomAppTransition customAnim =
+ topActivity.getCustomAnimation(open);
+ if (customAnim != null) {
+ if (animOptions == null) {
+ animOptions = TransitionInfo.AnimationOptions
+ .makeCommonAnimOptions(topActivity.packageName);
+ }
+ animOptions.addCustomActivityTransition(open, customAnim.mEnterAnim,
+ customAnim.mExitAnim, customAnim.mBackgroundColor);
+ }
+ return animOptions;
+ }
/**
* Finds the top-most common ancestor of app targets.
*
@@ -2019,7 +2047,13 @@
final DisplayContent dc = wc.asDisplayContent();
if (dc == null || !mChanges.get(dc).hasChanged()) continue;
dc.sendNewConfiguration();
- setReady(dc, true);
+ // Set to ready if no other change controls the ready state. But if there is, such as
+ // if an activity is pausing, it will call setReady(ar, false) and wait for the next
+ // resumed activity. Then do not set to ready because the transition only contains
+ // partial participants. Otherwise the transition may only handle HIDE and miss OPEN.
+ if (!mReadyTracker.mUsed) {
+ setReady(dc, true);
+ }
}
}
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index db7fced..77e8324 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -110,6 +110,15 @@
return array;
}
+static jboolean nativeGetHdrOutputConversionSupport(JNIEnv* env, jclass clazz) {
+ bool isSupported;
+ status_t err = SurfaceComposerClient::getHdrOutputConversionSupport(&isSupported);
+ if (err == OK) {
+ return isSupported;
+ }
+ return JNI_FALSE;
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
ScopedLongArrayRW values(env, env->NewLongArray(displayIds.size()));
@@ -150,6 +159,8 @@
(void*)nativeSetHdrConversionMode },
{"nativeGetSupportedHdrOutputTypes", "()[I",
(void*)nativeGetSupportedHdrOutputTypes },
+ {"nativeGetHdrOutputConversionSupport", "()Z",
+ (void*) nativeGetHdrOutputConversionSupport },
// clang-format on
};
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index d7a2095..88b82d7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -176,7 +176,8 @@
private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
-
+ // If the ActiveAdmin is a permission-based admin, then info will be null because the
+ // permission-based admin is not mapped to a device administrator component.
DeviceAdminInfo info;
static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
@@ -378,9 +379,11 @@
void writeToXml(TypedXmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
- out.startTag(null, TAG_POLICIES);
- info.writePoliciesToXml(out);
- out.endTag(null, TAG_POLICIES);
+ if (info != null) {
+ out.startTag(null, TAG_POLICIES);
+ info.writePoliciesToXml(out);
+ out.endTag(null, TAG_POLICIES);
+ }
if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) {
writeAttributeValueToXml(
out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality);
@@ -1188,14 +1191,16 @@
pw.print("testOnlyAdmin=");
pw.println(testOnlyAdmin);
- pw.println("policies:");
- ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
- if (pols != null) {
- pw.increaseIndent();
- for (int i = 0; i < pols.size(); i++) {
- pw.println(pols.get(i).tag);
+ if (info != null) {
+ pw.println("policies:");
+ ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
+ if (pols != null) {
+ pw.increaseIndent();
+ for (int i = 0; i < pols.size(); i++) {
+ pw.println(pols.get(i).tag);
+ }
+ pw.decreaseIndent();
}
- pw.decreaseIndent();
}
pw.print("passwordQuality=0x");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 8e430b3..a5b9d43 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -123,6 +123,23 @@
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
+ // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that
+ // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be
+ // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies
+ // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList
+ // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName.
+ // Instead, use variants of DPMS active admin getters to include the permission-based admin.
+ ActiveAdmin mPermissionBasedAdmin;
+
+ // Create or get the permission-based admin. The permission-based admin will not have a
+ // DeviceAdminInfo or ComponentName.
+ ActiveAdmin createOrGetPermissionBasedAdmin() {
+ if (mPermissionBasedAdmin == null) {
+ mPermissionBasedAdmin = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ }
+ return mPermissionBasedAdmin;
+ }
+
// TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
@@ -256,6 +273,12 @@
}
}
+ if (policyData.mPermissionBasedAdmin != null) {
+ out.startTag(null, "permission-based-admin");
+ policyData.mPermissionBasedAdmin.writeToXml(out);
+ out.endTag(null, "permission-based-admin");
+ }
+
if (policyData.mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
out.attributeInt(null, "value", policyData.mPasswordOwner);
@@ -457,6 +480,7 @@
policy.mLockTaskPackages.clear();
policy.mAdminList.clear();
policy.mAdminMap.clear();
+ policy.mPermissionBasedAdmin = null;
policy.mAffiliationIds.clear();
policy.mOwnerInstalledCaCerts.clear();
policy.mUserControlDisabledPackages = null;
@@ -484,6 +508,10 @@
} catch (RuntimeException e) {
Slogf.w(TAG, e, "Failed loading admin %s", name);
}
+ } else if ("permission-based-admin".equals(tag)) {
+ ActiveAdmin ap = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ ap.readFromXml(parser, /* overwritePolicies= */ false);
+ policy.mPermissionBasedAdmin = ap;
} else if ("delegation".equals(tag)) {
// Parse delegation info.
final String delegatePackage = parser.getAttributeValue(null,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cdcfaba..c847aa2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
@@ -33,10 +34,12 @@
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
@@ -44,7 +47,6 @@
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED;
-import static android.app.admin.DevicePolicyManager.AUTO_TIMEZONE_POLICY;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
@@ -62,6 +64,7 @@
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_APP_STANDBY;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_HIBERNATION;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
@@ -142,6 +145,9 @@
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_BODY;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON;
import static android.app.admin.ProvisioningException.ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED;
import static android.app.admin.ProvisioningException.ERROR_PRE_CONDITION_FAILED;
import static android.app.admin.ProvisioningException.ERROR_PROFILE_CREATION_FAILED;
@@ -149,6 +155,8 @@
import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -731,6 +739,9 @@
OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION);
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_HIBERNATION, OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION);
+ APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
+ EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
+ OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION);
}
/**
@@ -1157,6 +1168,12 @@
} else if (ACTION_TURN_PROFILE_ON_NOTIFICATION.equals(action)) {
Slogf.i(LOG_TAG, "requesting to turn on the profile: " + userHandle);
mUserManager.requestQuietModeEnabled(false, UserHandle.of(userHandle));
+ } else if (ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+ notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle.of(userHandle), /* managedProfileAvailable= */ false);
+ } else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) {
+ notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle.of(userHandle), /* managedProfileAvailable= */ true);
}
}
@@ -2001,7 +2018,8 @@
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
@@ -4168,6 +4186,27 @@
}
/**
+ * Get the list of active admins for an affected user:
+ * <ul>
+ * <li>The active admins associated with the userHandle itself</li>
+ * <li>The parent active admins for each managed profile associated with the userHandle</li>
+ * <li>The permission based admin associated with the userHandle itself</li>
+ * </ul>
+ *
+ * @param userHandle the affected user for whom to get the active admins
+ * @return the list of active admins for the affected user
+ */
+ @GuardedBy("getLockObject()")
+ private List<ActiveAdmin> getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+ int userHandle) {
+ List<ActiveAdmin> list = getActiveAdminsForAffectedUserLocked(userHandle);
+ if (getUserData(userHandle).mPermissionBasedAdmin != null) {
+ list.add(getUserData(userHandle).mPermissionBasedAdmin);
+ }
+ return list;
+ }
+
+ /**
* Returns the list of admins on the given user, as well as parent admins for each managed
* profile associated with the given user. Optionally also include the admin of each managed
* profile.
@@ -8472,24 +8511,39 @@
* Disables all device cameras according to the specified admin.
*/
@Override
- public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) {
+ public void setCameraDisabled(ComponentName who, String callerPackageName, boolean disabled,
+ boolean parent) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- if (parent) {
- Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
- }
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final int userHandle = caller.getUserId();
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED);
- final int userHandle = caller.getUserId();
+ ActiveAdmin admin = null;
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ callerPackageName,
+ getProfileParentUserIfRequested(userHandle, parent));
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ if (parent) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller));
+ }
+ synchronized (getLockObject()) {
+ admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
+ }
+ }
+
synchronized (getLockObject()) {
- ActiveAdmin ap = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
- if (ap.disableCamera != disabled) {
- ap.disableCamera = disabled;
+ if (admin.disableCamera != disabled) {
+ admin.disableCamera = disabled;
saveSettingsLocked(userHandle);
}
}
@@ -8518,14 +8572,19 @@
if (!mHasFeature) {
return false;
}
-
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
- || isCameraServerUid(caller));
-
- if (parent) {
+ if (isPermissionCheckFlagEnabled()) {
Preconditions.checkCallAuthorization(
- isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+ hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller)
+ || hasPermission(MANAGE_DEVICE_POLICY_CAMERA, userHandle)
+ || hasPermission(QUERY_ADMIN_POLICY));
+ } else {
+ Preconditions.checkCallAuthorization(
+ hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller));
+ if (parent) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+ }
}
synchronized (getLockObject()) {
@@ -8538,12 +8597,19 @@
if (deviceOwner != null && deviceOwner.disableCamera) {
return true;
}
- final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+ List<ActiveAdmin> admins;
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ if (isPermissionCheckFlagEnabled()) {
+ admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+ affectedUserId);
+ } else {
+ admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+ }
// Determine whether or not the device camera is disabled for any active admins.
- for (ActiveAdmin admin : admins) {
- if (admin.disableCamera) {
+ for (ActiveAdmin activeAdmin : admins) {
+ if (activeAdmin.disableCamera) {
return true;
}
}
@@ -13776,6 +13842,26 @@
return false;
}
+ @Override
+ public boolean isStatusBarDisabled(String callerPackage) {
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+
+ int userId = caller.getUserId();
+ synchronized (getLockObject()) {
+ Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
+ "Admin " + callerPackage
+ + " is neither the device owner or affiliated user's profile owner.");
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable status bar");
+ }
+ DevicePolicyData policy = getUserData(userId);
+ return policy.mStatusBarDisabled;
+ }
+ }
+
+
/**
* We need to update the internal state of whether a user has completed setup or a
* device has paired once. After that, we ignore any changes that reset the
@@ -15601,6 +15687,7 @@
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -15631,6 +15718,7 @@
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -18679,6 +18767,83 @@
});
}
+ private void notifyIfManagedSubscriptionsAreUnavailable(
+ UserHandle managedProfile, boolean managedProfileAvailable) {
+ if (!isManagedProfile(managedProfile.getIdentifier())) {
+ Slog.wtf(
+ LOG_TAG,
+ "Expected managed profile when notified of profile availability change.");
+ }
+ if (getManagedSubscriptionsPolicy().getPolicyType()
+ != ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
+ // There may be a subscription in the personal profile, in which case calls and
+ // texts may still be available. No need to notify the user.
+ return;
+ }
+ if (managedProfileAvailable) {
+ // When quiet mode is switched off calls and texts then become available to the user,
+ // so no need to keep showing the notification.
+ mInjector
+ .getNotificationManager()
+ .cancel(SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF);
+ return;
+ }
+ final Intent intent = new Intent(ACTION_TURN_PROFILE_ON_NOTIFICATION);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, managedProfile.getIdentifier());
+ final PendingIntent pendingIntent =
+ mInjector.pendingIntentGetBroadcast(
+ mContext,
+ /* requestCode= */ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ final Notification.Action turnProfileOnButton =
+ new Notification.Action.Builder(
+ /* icon= */ null, getUnpauseWorkAppsButtonText(), pendingIntent)
+ .build();
+
+ final Bundle extras = new Bundle();
+ extras.putString(
+ Notification.EXTRA_SUBSTITUTE_APP_NAME, getWorkProfileContentDescription());
+ final Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(R.drawable.ic_phone_disabled)
+ .setContentTitle(getUnpauseWorkAppsForTelephonyTitle())
+ .setContentText(getUnpauseWorkAppsForTelephonyText())
+ .setStyle(new Notification.BigTextStyle().bigText(
+ getUnpauseWorkAppsForTelephonyText()))
+ .addAction(turnProfileOnButton)
+ .addExtras(extras)
+ .setOngoing(false)
+ .setShowWhen(true)
+ .setAutoCancel(true)
+ .build();
+
+ mInjector
+ .getNotificationManager()
+ .notifyAsUser(
+ /* tag= */ null,
+ SystemMessage.NOTE_ALL_MANAGED_SUBSCRIPTIONS_AND_MANAGED_PROFILE_OFF,
+ notification,
+ UserHandle.of(getProfileParentId(managedProfile.getIdentifier())));
+ }
+
+ private String getUnpauseWorkAppsButtonText() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON,
+ R.string.work_profile_telephony_paused_turn_on_button);
+ }
+
+ private String getUnpauseWorkAppsForTelephonyTitle() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_TITLE, R.string.work_profile_telephony_paused_title);
+ }
+
+ private String getUnpauseWorkAppsForTelephonyText() {
+ return getUpdatableString(
+ WORK_PROFILE_TELEPHONY_PAUSED_BODY,
+ R.string.work_profile_telephony_paused_text);
+ }
+
@GuardedBy("getLockObject()")
private void updateProfileOffDeadlineNotificationLocked(
int profileUserId, ActiveAdmin profileOwner, int notificationState) {
@@ -19049,7 +19214,7 @@
}
setUserSetupComplete(userInfo.id);
- startUser(userInfo.id, callerPackage);
+ startProfileForSetup(userInfo.id, callerPackage);
maybeMigrateAccount(
userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
provisioningParams.isKeepingAccountOnMigration(), callerPackage);
@@ -19280,8 +19445,9 @@
mContext.getContentResolver(), USER_SETUP_COMPLETE, 1, userId);
}
- private void startUser(@UserIdInt int userId, String callerPackage)
+ private void startProfileForSetup(@UserIdInt int userId, String callerPackage)
throws IllegalStateException {
+ Slogf.i(LOG_TAG, "Starting profile %d as requested by package %s", userId, callerPackage);
final long startTime = SystemClock.elapsedRealtime();
final UserUnlockedBlockingReceiver unlockedReceiver = new UserUnlockedBlockingReceiver(
userId);
@@ -19292,7 +19458,8 @@
/* broadcastPermission = */ null,
/* scheduler= */ null);
try {
- if (!mInjector.getIActivityManager().startUserInBackground(userId)) {
+ // Must call startProfileEvenWhenDisabled(), as profile is not enabled yet
+ if (!mInjector.getActivityManagerInternal().startProfileEvenWhenDisabled(userId)) {
throw new ServiceSpecificException(ERROR_STARTING_PROFILE_FAILED,
String.format("Unable to start user %d in background", userId));
}
@@ -19305,9 +19472,6 @@
DevicePolicyEnums.PLATFORM_PROVISIONING_START_PROFILE_MS,
startTime,
callerPackage);
- } catch (RemoteException e) {
- // Shouldn't happen.
- Slogf.wtf(LOG_TAG, "Error starting user", e);
} finally {
mContext.unregisterReceiver(unlockedReceiver);
}
@@ -20404,9 +20568,9 @@
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
- String permission, int targetUserId) {
+ String permission, String callerPackageName, int targetUserId) {
enforcePermission(permission, targetUserId);
- return getEnforcingAdminForCaller(admin, getCallerIdentity());
+ return getEnforcingAdminForCaller(admin, callerPackageName);
}
/**
@@ -20421,9 +20585,9 @@
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforceCanQueryAndGetEnforcingAdmin(@Nullable ComponentName admin,
- String permission, int targetUserId) {
+ String permission, String callerPackageName, int targetUserId) {
enforceCanQuery(permission, targetUserId);
- return getEnforcingAdminForCaller(admin, getCallerIdentity());
+ return getEnforcingAdminForCaller(admin, callerPackageName);
}
private static final HashMap<String, String> POLICY_IDENTIFIER_TO_PERMISSION = new HashMap<>();
@@ -20567,7 +20731,8 @@
}
private EnforcingAdmin getEnforcingAdminForCaller(@Nullable ComponentName who,
- CallerIdentity caller) {
+ String callerPackageName) {
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
int userId = caller.getUserId();
ActiveAdmin admin = null;
synchronized (getLockObject()) {
@@ -20579,7 +20744,10 @@
if (getActiveAdminUncheckedLocked(who, userId) != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
- return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId);
+ if (admin == null) {
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin();
+ }
+ return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
private boolean isPermissionCheckFlagEnabled() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 10e972d..a303fde 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -19,10 +19,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.Authority;
-import android.app.admin.UnknownAuthority;
import android.app.admin.DeviceAdminAuthority;
import android.app.admin.DpcAuthority;
import android.app.admin.RoleAuthority;
+import android.app.admin.UnknownAuthority;
import android.content.ComponentName;
import android.os.UserHandle;
@@ -71,9 +71,10 @@
private final boolean mIsRoleAuthority;
private final ActiveAdmin mActiveAdmin;
- static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId) {
+ static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId,
+ ActiveAdmin admin) {
Objects.requireNonNull(packageName);
- return new EnforcingAdmin(packageName, userId);
+ return new EnforcingAdmin(packageName, userId, admin);
}
static EnforcingAdmin createEnterpriseEnforcingAdmin(
@@ -111,6 +112,23 @@
return ROLE_AUTHORITY_PREFIX + roleName;
}
+ static Authority getParcelableAuthority(String authority) {
+ if (authority == null || authority.isEmpty()) {
+ return UnknownAuthority.UNKNOWN_AUTHORITY;
+ }
+ if (DPC_AUTHORITY.equals(authority)) {
+ return DpcAuthority.DPC_AUTHORITY;
+ }
+ if (DEVICE_ADMIN_AUTHORITY.equals(authority)) {
+ return DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
+ }
+ if (authority.startsWith(ROLE_AUTHORITY_PREFIX)) {
+ String role = authority.substring(ROLE_AUTHORITY_PREFIX.length());
+ return new RoleAuthority(Set.of(role));
+ }
+ return UnknownAuthority.UNKNOWN_AUTHORITY;
+ }
+
private EnforcingAdmin(
String packageName, ComponentName componentName, Set<String> authorities, int userId,
ActiveAdmin activeAdmin) {
@@ -127,7 +145,7 @@
mActiveAdmin = activeAdmin;
}
- private EnforcingAdmin(String packageName, int userId) {
+ private EnforcingAdmin(String packageName, int userId, ActiveAdmin activeAdmin) {
Objects.requireNonNull(packageName);
// Only role authorities use this constructor.
@@ -137,7 +155,7 @@
mComponentName = null;
// authorities will be loaded when needed
mAuthorities = null;
- mActiveAdmin = null;
+ mActiveAdmin = activeAdmin;
}
private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -274,7 +292,7 @@
int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
if (isRoleAuthority) {
- return new EnforcingAdmin(packageName, userId);
+ return new EnforcingAdmin(packageName, userId, null);
} else {
String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME);
ComponentName componentName = new ComponentName(packageName, className);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 9e0da26..21c9434 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.BooleanPolicyValue;
+import android.app.admin.DevicePolicyIdentifiers;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IntegerPolicyValue;
import android.app.admin.IntentFilterPolicyKey;
@@ -73,7 +74,7 @@
List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.AUTO_TIMEZONE_POLICY),
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
// auto timezone is disabled by default, hence enabling it is more restrictive.
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
@@ -86,7 +87,7 @@
// when reading the policies from xml.
static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
new PolicyDefinition<>(
- new PackagePermissionPolicyKey(DevicePolicyManager.PERMISSION_GRANT_POLICY),
+ new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
// TODO: is this really the best mechanism, what makes denied more
// restrictive than
// granted?
@@ -113,16 +114,17 @@
}
return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
new PackagePermissionPolicyKey(
- DevicePolicyManager.PERMISSION_GRANT_POLICY,
+ DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
packageName,
permissionName));
}
static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.LOCK_TASK_POLICY),
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
// TODO(b/258166155): add correct device lock role name
- EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.getRoleAuthorityOf(
+ "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
(LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
@@ -131,7 +133,8 @@
static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES =
new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY),
+ new NoArgsPolicyKey(
+ DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
new StringSetUnion(),
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
@@ -143,10 +146,11 @@
static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
new PolicyDefinition<>(
new IntentFilterPolicyKey(
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
new TopPriority<>(List.of(
// TODO(b/258166155): add correct device lock role name
- EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.getRoleAuthorityOf(
+ "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::addPersistentPreferredActivity,
@@ -163,7 +167,8 @@
}
return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
new IntentFilterPolicyKey(
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY, intentFilter));
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ intentFilter));
}
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -172,7 +177,7 @@
static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
new PolicyDefinition<>(
new PackagePolicyKey(
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY),
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::setUninstallBlocked,
@@ -189,7 +194,7 @@
}
return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
new PackagePolicyKey(
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
}
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -198,7 +203,7 @@
static PolicyDefinition<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
new PolicyDefinition<>(
new PackagePolicyKey(
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY),
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY),
// Don't need to take in a resolution mechanism since its never used, but might
// need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
@@ -220,11 +225,11 @@
}
return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
new PackagePolicyKey(
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, packageName));
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, packageName));
}
static PolicyDefinition<Long> RESET_PASSWORD_TOKEN = new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.RESET_PASSWORD_TOKEN_POLICY),
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY),
// Don't need to take in a resolution mechanism since its never used, but might
// need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
@@ -234,19 +239,21 @@
new LongPolicySerializer());
private static final Map<String, PolicyDefinition<?>> sPolicyDefinitions = Map.of(
- DevicePolicyManager.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
- DevicePolicyManager.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
- DevicePolicyManager.LOCK_TASK_POLICY, LOCK_TASK,
- DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+ DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
+ DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
+ DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK,
+ DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
USER_CONTROLLED_DISABLED_PACKAGES,
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
GENERIC_PERSISTENT_PREFERRED_ACTIVITY,
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, GENERIC_PACKAGE_UNINSTALL_BLOCKED,
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, GENERIC_APPLICATION_RESTRICTIONS,
- DevicePolicyManager.RESET_PASSWORD_TOKEN_POLICY, RESET_PASSWORD_TOKEN
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
+ GENERIC_PACKAGE_UNINSTALL_BLOCKED,
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
+ GENERIC_APPLICATION_RESTRICTIONS,
+ DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
+ RESET_PASSWORD_TOKEN
);
-
private final PolicyKey mPolicyKey;
private final ResolutionMechanism<V> mResolutionMechanism;
private final int mPolicyFlags;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
index 839840b..825157f0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
@@ -17,8 +17,10 @@
package com.android.server.devicepolicy;
import android.annotation.NonNull;
+import android.app.admin.Authority;
import android.app.admin.PolicyValue;
+import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -54,7 +56,15 @@
@Override
android.app.admin.TopPriority<V> getParcelableResolutionMechanism() {
- return new android.app.admin.TopPriority<>(mHighestToLowestPriorityAuthorities);
+ return new android.app.admin.TopPriority<>(getParcelableAuthorities());
+ }
+
+ private List<Authority> getParcelableAuthorities() {
+ List<Authority> authorities = new ArrayList<>();
+ for (String authority : mHighestToLowestPriorityAuthorities) {
+ authorities.add(EnforcingAdmin.getParcelableAuthority(authority));
+ }
+ return authorities;
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b117cae..850b5b6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2095,6 +2095,14 @@
mSystemServiceManager.startService(DeviceStorageMonitorService.class);
t.traceEnd();
+ t.traceBegin("StartTimeDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting TimeDetectorService service", e);
+ }
+ t.traceEnd();
+
t.traceBegin("StartLocationManagerService");
mSystemServiceManager.startService(LocationManagerService.Lifecycle.class);
t.traceEnd();
@@ -2108,14 +2116,6 @@
}
t.traceEnd();
- t.traceBegin("StartTimeDetectorService");
- try {
- mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting TimeDetectorService service", e);
- }
- t.traceEnd();
-
t.traceBegin("StartTimeZoneDetectorService");
try {
mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 61f8681..ef35010 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -18,6 +18,7 @@
import android.Manifest
import android.app.ActivityManager
+import android.app.AppOpsManager
import android.compat.annotation.ChangeId
import android.compat.annotation.EnabledAfter
import android.content.Context
@@ -59,10 +60,12 @@
import com.android.server.ServiceThread
import com.android.server.SystemConfig
import com.android.server.permission.access.AccessCheckingService
+import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.appop.UidAppOpPolicy
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.util.andInv
import com.android.server.permission.access.util.hasAnyBit
@@ -733,18 +736,46 @@
}
}
- private fun grantRequestedRuntimePermissions(
+ private fun setRequestedPermissionStates(
packageState: PackageState,
userId: Int,
- permissionNames: IndexedList<String>
+ permissionStates: IndexedMap<String, Int>
) {
service.mutateState {
- permissionNames.forEachIndexed { _, permissionName ->
- setRuntimePermissionGranted(
- packageState, userId, permissionName, isGranted = true,
- canManageRolePermission = false, overridePolicyFixed = false,
- reportError = false, "grantRequestedRuntimePermissions"
- )
+ permissionStates.forEachIndexed { _, permissionName, permissionState ->
+ when (permissionState) {
+ PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED,
+ PackageInstaller.SessionParams.PERMISSION_STATE_DENIED -> {}
+ else -> {
+ Log.w(
+ LOG_TAG, "setRequestedPermissionStates: Unknown permission state" +
+ " $permissionState for permission $permissionName"
+ )
+ return@forEachIndexed
+ }
+ }
+ if (permissionName !in packageState.androidPackage!!.requestedPermissions) {
+ return@forEachIndexed
+ }
+ val permission = with(policy) { getPermissions()[permissionName] }
+ ?: return@forEachIndexed
+ when {
+ permission.isDevelopment || permission.isRuntime -> {
+ if (permissionState ==
+ PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
+ setRuntimePermissionGranted(
+ packageState, userId, permissionName, isGranted = true,
+ canManageRolePermission = false, overridePolicyFixed = false,
+ reportError = false, "setRequestedPermissionStates"
+ )
+ }
+ }
+ permission.isAppOp -> setAppOpPermissionGranted(
+ packageState, userId, permissionName,
+ permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
+ )
+ else -> {}
+ }
}
}
}
@@ -890,6 +921,18 @@
}
}
+ private fun MutateStateScope.setAppOpPermissionGranted(
+ packageState: PackageState,
+ userId: Int,
+ permissionName: String,
+ isGranted: Boolean
+ ) {
+ val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as UidAppOpPolicy
+ val appOpName = AppOpsManager.permissionToOp(permissionName)
+ val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
+ with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
+ }
+
override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
Log.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
@@ -1814,15 +1857,7 @@
val packageState =
packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
// TODO: Add allowlisting
- grantRequestedRuntimePermissions(
- packageState,
- userId,
- params.permissionStates.mapNotNullIndexed { _, permissionName, permissionState ->
- permissionName.takeIf {
- permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
- }
- }
- )
+ setRequestedPermissionStates(packageState, userId, params.permissionStates)
}
}
diff --git a/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java b/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java
new file mode 100644
index 0000000..3e2e46c
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/gnss/TimeDetectorNetworkTimeHelperTest.java
@@ -0,0 +1,399 @@
+/*
+ * 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.server.location.gnss;
+
+import static com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.MAX_NETWORK_TIME_AGE_MILLIS;
+import static com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.NTP_REFRESH_INTERVAL_MILLIS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.time.UnixEpochTime;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.location.gnss.NetworkTimeHelper.InjectTimeCallback;
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper.Environment;
+import com.android.server.timedetector.NetworkTimeSuggestion;
+import com.android.server.timezonedetector.StateChangeListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Unit tests for {@link TimeDetectorNetworkTimeHelper}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class TimeDetectorNetworkTimeHelperTest {
+
+ private static final NetworkTimeSuggestion ARBITRARY_NETWORK_TIME =
+ new NetworkTimeSuggestion(new UnixEpochTime(1234L, 7777L), 123);
+
+ private FakeEnvironment mFakeEnvironment;
+ @Mock private InjectTimeCallback mMockInjectTimeCallback;
+ private TimeDetectorNetworkTimeHelper mTimeDetectorNetworkTimeHelper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mFakeEnvironment = new FakeEnvironment();
+ mTimeDetectorNetworkTimeHelper = new TimeDetectorNetworkTimeHelper(
+ mFakeEnvironment, mMockInjectTimeCallback);
+
+ // TimeDetectorNetworkTimeHelper should register for network time updates during
+ // construction.
+ mFakeEnvironment.assertHasNetworkTimeChangeListener();
+ }
+
+ @Test
+ public void setPeriodicTimeInjectionMode_true() {
+ testSetPeriodicTimeInjectionMode(true);
+ }
+
+ @Test
+ public void setPeriodicTimeInjectionMode_false() {
+ testSetPeriodicTimeInjectionMode(false);
+ }
+
+ private void testSetPeriodicTimeInjectionMode(boolean periodicTimeInjectionMode) {
+ NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+ int millisElapsedSinceNetworkTimeReceived = 1000;
+ mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+ long currentElapsedRealtimeMillis =
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis()
+ + millisElapsedSinceNetworkTimeReceived;
+ mFakeEnvironment.pokeElapsedRealtimeMillis(currentElapsedRealtimeMillis);
+
+ mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(periodicTimeInjectionMode);
+
+ // All injections are async, so we have to simulate the async work taking place.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+
+ // Any call to setPeriodicTimeInjectionMode() should result in an (async) injected time
+ verify(mMockInjectTimeCallback).injectTime(
+ networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+ networkTime.getUncertaintyMillis());
+
+ // Check whether the scheduled async is set up / not set up for the periodic request.
+ if (periodicTimeInjectionMode) {
+ mFakeEnvironment.assertHasScheduledAsyncCallback(
+ mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+ } else {
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ }
+ }
+
+ @Test
+ public void periodicInjectionBehavior() {
+ // Set the elapsed realtime clock to an arbitrary start value.
+ mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+ // Configure periodic time injections. Doing so should cause a time query, but no time is
+ // available.
+ mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(true);
+
+ // All query/injections are async, so we have to simulate the async work taking place.
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+
+ // No time available, so no injection.
+ verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+ // A periodic check should be scheduled.
+ mFakeEnvironment.assertHasScheduledAsyncCallback(
+ mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+
+ // Time passes...
+ mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+ // A network time becomes available: This should cause the registered listener to trigger.
+ NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+ mFakeEnvironment.simulateLatestNetworkTimeChange(networkTime);
+
+ // All query/injections are async, so we have to simulate the async work taking place,
+ // causing a query, time injection and a re-schedule.
+ mFakeEnvironment.simulateTimeAdvancing(1);
+ verify(mMockInjectTimeCallback).injectTime(
+ networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+ networkTime.getUncertaintyMillis());
+
+ // A new periodic check should be scheduled.
+ mFakeEnvironment.assertHasNoImmediateCallback();
+
+ mFakeEnvironment.assertHasScheduledAsyncCallback(
+ mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+
+ int arbitraryIterationCount = 3;
+ for (int i = 0; i < arbitraryIterationCount; i++) {
+ // Advance by the amount needed for the scheduled work to run. That work should query
+ // and inject.
+ mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS);
+
+ // All query/injections are async, so we have to simulate the async work taking place,
+ // causing a query, time injection and a re-schedule.
+ verify(mMockInjectTimeCallback).injectTime(
+ networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+ networkTime.getUncertaintyMillis());
+
+ // A new periodic check should be scheduled.
+ mFakeEnvironment.assertHasScheduledAsyncCallback(
+ mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+ mFakeEnvironment.assertHasNoImmediateCallback();
+ }
+ }
+
+ @Test
+ public void networkTimeAvailableBehavior() {
+ // Set the elapsed realtime clock to an arbitrary start value.
+ mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+ // No periodic time injections. This call causes a time query, but no time is available yet.
+ mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(false);
+
+ // All query/injections are async, so we have to simulate the async work taking place.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+
+ // No time available, so no injection.
+ verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+ // No periodic check should be scheduled.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+
+ // Time passes...
+ mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+ // A network time becomes available: This should cause the registered listener to trigger
+ // and cause time to be injected.
+ NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+ mFakeEnvironment.simulateLatestNetworkTimeChange(networkTime);
+
+ // All query/injections are async, so we have to simulate the async work taking place,
+ // causing a query, time injection and a re-schedule.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+ verify(mMockInjectTimeCallback).injectTime(
+ networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+ networkTime.getUncertaintyMillis());
+
+ // No periodic check should be scheduled.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasNoImmediateCallback();
+ }
+
+ @Test
+ public void networkConnectivityAvailableBehavior() {
+ // Set the elapsed realtime clock to an arbitrary start value.
+ mFakeEnvironment.pokeElapsedRealtimeMillis(12345L);
+
+ // No periodic time injections. This call causes a time query, but no time is available yet.
+ mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(false);
+
+ // All query/injections are async, so we have to simulate the async work taking place.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+
+ // No time available, so no injection.
+ verifyNoMoreInteractions(mMockInjectTimeCallback);
+
+ // No periodic check should be scheduled.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+
+ // Time passes...
+ mFakeEnvironment.simulateTimeAdvancing(NTP_REFRESH_INTERVAL_MILLIS / 2);
+
+ NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+ mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+ // Simulate location code noticing that connectivity has changed and notifying the helper.
+ mTimeDetectorNetworkTimeHelper.onNetworkAvailable();
+
+ // All query/injections are async, so we have to simulate the async work taking place,
+ // causing a query, time injection and a re-schedule.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+ mFakeEnvironment.simulateTimeAdvancing(1);
+ verify(mMockInjectTimeCallback).injectTime(
+ networkTime.getUnixEpochTime().getUnixEpochTimeMillis(),
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis(),
+ networkTime.getUncertaintyMillis());
+
+ // No periodic check should be scheduled.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasNoImmediateCallback();
+ }
+
+ @Test
+ public void oldTimesNotInjected() {
+ NetworkTimeSuggestion networkTime = ARBITRARY_NETWORK_TIME;
+ mFakeEnvironment.pokeLatestNetworkTime(networkTime);
+
+ int millisElapsedSinceNetworkTimeReceived = MAX_NETWORK_TIME_AGE_MILLIS;
+ long currentElapsedRealtimeMillis =
+ networkTime.getUnixEpochTime().getElapsedRealtimeMillis()
+ + millisElapsedSinceNetworkTimeReceived;
+ mFakeEnvironment.pokeElapsedRealtimeMillis(currentElapsedRealtimeMillis);
+
+ mTimeDetectorNetworkTimeHelper.setPeriodicTimeInjectionMode(true);
+
+ // All injections are async, so we have to simulate the async work taking place.
+ mFakeEnvironment.assertHasNoScheduledAsyncCallback();
+ mFakeEnvironment.assertHasImmediateCallback();
+
+ // The age of the network time will now be MAX_NETWORK_TIME_AGE_MILLIS + 1, which is too
+ // old to inject.
+ mFakeEnvironment.simulateTimeAdvancing(1);
+
+ // Old network times should not be injected.
+ verify(mMockInjectTimeCallback, never()).injectTime(anyLong(), anyLong(), anyInt());
+
+ // Check whether the scheduled async is set up / not set up for the periodic request.
+ mFakeEnvironment.assertHasScheduledAsyncCallback(
+ mFakeEnvironment.elapsedRealtimeMillis() + NTP_REFRESH_INTERVAL_MILLIS);
+ }
+
+ /** A fake implementation of {@link Environment} for use by this test. */
+ private static class FakeEnvironment implements Environment {
+
+ private StateChangeListener mNetworkTimeUpdateListener;
+
+ private long mCurrentElapsedRealtimeMillis;
+ private NetworkTimeSuggestion mLatestNetworkTime;
+
+ private TimeDetectorNetworkTimeHelper mImmediateAsyncCallback;
+ private String mImmediateAsyncCallbackReason;
+
+ private TimeDetectorNetworkTimeHelper mScheduledAsyncCallback;
+ private long mScheduledAsyncRunnableTimeMillis;
+
+ @Override
+ public long elapsedRealtimeMillis() {
+ return mCurrentElapsedRealtimeMillis;
+ }
+
+ @Override
+ public NetworkTimeSuggestion getLatestNetworkTime() {
+ return mLatestNetworkTime;
+ }
+
+ @Override
+ public void setNetworkTimeUpdateListener(StateChangeListener stateChangeListener) {
+ mNetworkTimeUpdateListener = stateChangeListener;
+ }
+
+ @Override
+ public void requestImmediateTimeQueryCallback(TimeDetectorNetworkTimeHelper helper,
+ String reason) {
+ if (mImmediateAsyncCallback != null) {
+ fail("Only one immediate callback expected at a time, found reason: "
+ + mImmediateAsyncCallbackReason);
+ }
+ mImmediateAsyncCallback = helper;
+ mImmediateAsyncCallbackReason = reason;
+ }
+
+ @Override
+ public void requestDelayedTimeQueryCallback(
+ TimeDetectorNetworkTimeHelper instance, long delayMillis) {
+ mScheduledAsyncCallback = instance;
+ mScheduledAsyncRunnableTimeMillis = mCurrentElapsedRealtimeMillis + delayMillis;
+ }
+
+ @Override
+ public void clearDelayedTimeQueryCallback() {
+ mScheduledAsyncCallback = null;
+ mScheduledAsyncRunnableTimeMillis = -1;
+ }
+
+ void pokeLatestNetworkTime(NetworkTimeSuggestion networkTime) {
+ mLatestNetworkTime = networkTime;
+ }
+
+ void pokeElapsedRealtimeMillis(long currentElapsedRealtimeMillis) {
+ mCurrentElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+ }
+
+ void simulateLatestNetworkTimeChange(NetworkTimeSuggestion networkTime) {
+ mLatestNetworkTime = networkTime;
+ mNetworkTimeUpdateListener.onChange();
+ }
+
+ void simulateTimeAdvancing(long durationMillis) {
+ mCurrentElapsedRealtimeMillis += durationMillis;
+
+ if (mImmediateAsyncCallback != null) {
+ TimeDetectorNetworkTimeHelper helper = mImmediateAsyncCallback;
+ String reason = mImmediateAsyncCallbackReason;
+ mImmediateAsyncCallback = null;
+ mImmediateAsyncCallbackReason = null;
+ helper.queryAndInjectNetworkTime(reason);
+ }
+
+ if (mScheduledAsyncCallback != null
+ && mCurrentElapsedRealtimeMillis >= mScheduledAsyncRunnableTimeMillis) {
+ TimeDetectorNetworkTimeHelper helper = mScheduledAsyncCallback;
+ mScheduledAsyncCallback = null;
+ mScheduledAsyncRunnableTimeMillis = -1;
+ helper.delayedQueryAndInjectNetworkTime();
+ }
+ }
+
+ void assertHasNetworkTimeChangeListener() {
+ assertNotNull(mNetworkTimeUpdateListener);
+ }
+
+ void assertHasImmediateCallback() {
+ assertNotNull(mImmediateAsyncCallback);
+ }
+
+ void assertHasNoImmediateCallback() {
+ assertNull(mImmediateAsyncCallback);
+ }
+
+ void assertHasScheduledAsyncCallback(long expectedScheduledAsyncRunnableTimeMillis) {
+ assertNotNull(mScheduledAsyncCallback);
+ assertEquals(expectedScheduledAsyncRunnableTimeMillis,
+ mScheduledAsyncRunnableTimeMillis);
+ }
+
+ void assertHasNoScheduledAsyncCallback() {
+ assertNull(mScheduledAsyncCallback);
+ }
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 31c49b3..9c4e6fd 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -33,6 +33,7 @@
"Harrier",
],
platform_apis: true,
+ certificate: "platform",
test_suites: ["device-tests"],
data: [
":AppEnumerationCrossUserPackageVisibilityTestApp",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
index 0395aa8..4749419 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
@@ -25,6 +25,7 @@
<!-- It's merged from Harrier library. Remove it since this test should not hold it. -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:node="remove" />
+ <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.appenumeration"
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index 31fe184..4012d8e 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -16,6 +16,8 @@
package com.android.server.pm.test.appenumeration;
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
@@ -26,7 +28,10 @@
import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -160,6 +165,31 @@
null /* onFinished */, null /* handler */));
}
+ @Test
+ public void mediaProjectionManager_createProjection_canSeeForceQueryable()
+ throws Exception {
+ installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+ assertThat(mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */))
+ .isNotNull();
+ }
+
+ @Test
+ public void mediaProjectionManager_createProjection_cannotSeeTarget() {
+ installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */));
+ }
+
private static void installPackage(String apkPath, boolean forceQueryable) {
final StringBuilder cmd = new StringBuilder("pm install ");
if (forceQueryable) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
index d760dc7..811b086 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.server.pm
-import android.Manifest
import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
@@ -122,12 +121,10 @@
writeRestoreAssert(sessions).single().params.run {
assertThat(legacyGrantedRuntimePermissions).asList()
.containsExactly("grantPermission", "denyToGrantPermission")
- assertThat(finalPermissionStates)
+ assertThat(permissionStates)
.containsExactlyEntriesIn(mapOf(
"grantPermission" to PERMISSION_STATE_GRANTED,
"denyToGrantPermission" to PERMISSION_STATE_GRANTED,
- // Fullscreen Intent is auto-granted if the caller has no opinion
- Manifest.permission.USE_FULL_SCREEN_INTENT to PERMISSION_STATE_GRANTED,
"denyPermission" to PERMISSION_STATE_DENIED,
"grantToDenyPermission" to PERMISSION_STATE_DENIED,
))
@@ -282,7 +279,7 @@
assertThat(expected.referrerUri).isEqualTo(actual.referrerUri)
assertThat(expected.abiOverride).isEqualTo(actual.abiOverride)
assertThat(expected.volumeUuid).isEqualTo(actual.volumeUuid)
- assertThat(expected.finalPermissionStates).isEqualTo(actual.finalPermissionStates)
+ assertThat(expected.permissionStates).isEqualTo(actual.permissionStates)
assertThat(expected.installerPackageName).isEqualTo(actual.installerPackageName)
assertThat(expected.isMultiPackage).isEqualTo(actual.isMultiPackage)
assertThat(expected.isStaged).isEqualTo(actual.isStaged)
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 9895e7c..c7fb32c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -753,7 +753,7 @@
.setPVersionCode(pkg.getLongVersionCode())
.setPkgFlags(PackageInfoUtils.appInfoFlags(pkg, null))
.setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(pkg, null))
- .setSharedUserId(pkg.getSharedUserLabelRes())
+ .setSharedUserId(pkg.getSharedUserLabelResourceId())
.build();
}
@@ -763,13 +763,13 @@
assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
assertEquals(a.isHardwareAccelerated(), b.isHardwareAccelerated());
assertEquals(a.getLongVersionCode(), b.getLongVersionCode());
- assertEquals(a.getSharedUserLabelRes(), b.getSharedUserLabelRes());
+ assertEquals(a.getSharedUserLabelResourceId(), b.getSharedUserLabelResourceId());
assertEquals(a.getInstallLocation(), b.getInstallLocation());
assertEquals(a.isCoreApp(), b.isCoreApp());
assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
- assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+ assertEquals(a.is32BitAbiPreferred(), b.is32BitAbiPreferred());
assertEquals(a.getPackageName(), b.getPackageName());
assertArrayEquals(a.getSplitNames(), b.getSplitNames());
assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
@@ -1039,7 +1039,7 @@
((ParsedPackage) pkg.setBaseRevisionCode(100)
.setHardwareAccelerated(true)
- .setSharedUserLabelRes(100)
+ .setSharedUserLabelResourceId(100)
.setInstallLocation(100)
.setRequiredForAllUsers(true)
.asSplit(
@@ -1048,7 +1048,7 @@
new int[]{100},
null
)
- .setUse32BitAbi(true)
+ .set32BitAbiPreferred(true)
.setVolumeUuid("d52ef59a-7def-4541-bf21-4c28ed4b65a0")
.addPermission(permission)
.addPermissionGroup(new ParsedPermissionGroupImpl())
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 0b7020c7..6d3cdff 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -155,7 +155,7 @@
AndroidPackage::getAppComponentFactory,
AndroidPackage::getAutoRevokePermissions,
AndroidPackage::getBackupAgentName,
- AndroidPackage::getBannerRes,
+ AndroidPackage::getBannerResourceId,
AndroidPackage::getBaseApkPath,
AndroidPackage::getBaseRevisionCode,
AndroidPackage::getCategory,
@@ -163,16 +163,16 @@
AndroidPackage::getCompatibleWidthLimitDp,
AndroidPackage::getCompileSdkVersion,
AndroidPackage::getCompileSdkVersionCodeName,
- AndroidPackage::getDataExtractionRulesRes,
- AndroidPackage::getDescriptionRes,
- AndroidPackage::getFullBackupContentRes,
+ AndroidPackage::getDataExtractionRulesResourceId,
+ AndroidPackage::getDescriptionResourceId,
+ AndroidPackage::getFullBackupContentResourceId,
AndroidPackage::getGwpAsanMode,
- AndroidPackage::getIconRes,
+ AndroidPackage::getIconResourceId,
AndroidPackage::getInstallLocation,
- AndroidPackage::getLabelRes,
+ AndroidPackage::getLabelResourceId,
AndroidPackage::getLargestWidthLimitDp,
- AndroidPackage::getLogoRes,
- AndroidPackage::getLocaleConfigRes,
+ AndroidPackage::getLogoResourceId,
+ AndroidPackage::getLocaleConfigResourceId,
AndroidPackage::getManageSpaceActivityName,
AndroidPackage::getMaxSdkVersion,
AndroidPackage::getMemtagMode,
@@ -180,7 +180,7 @@
AndroidPackage::getNativeHeapZeroInitialized,
AndroidPackage::getNativeLibraryDir,
AndroidPackage::getNativeLibraryRootDir,
- AndroidPackage::getNetworkSecurityConfigRes,
+ AndroidPackage::getNetworkSecurityConfigResourceId,
AndroidPackage::getNonLocalizedLabel,
AndroidPackage::getOverlayCategory,
AndroidPackage::getOverlayPriority,
@@ -195,11 +195,11 @@
AndroidPackage::getRequiresSmallestWidthDp,
AndroidPackage::getResizeableActivity,
AndroidPackage::getRestrictedAccountType,
- AndroidPackage::getRoundIconRes,
+ AndroidPackage::getRoundIconResourceId,
PackageImpl::getSecondaryCpuAbi,
AndroidPackage::getSecondaryNativeLibraryDir,
AndroidPackage::getSharedUserId,
- AndroidPackage::getSharedUserLabelRes,
+ AndroidPackage::getSharedUserLabelResourceId,
AndroidPackage::getSdkLibraryName,
AndroidPackage::getSdkLibVersionMajor,
AndroidPackage::getStaticSharedLibraryName,
@@ -207,21 +207,21 @@
AndroidPackage::getTargetSandboxVersion,
AndroidPackage::getTargetSdkVersion,
AndroidPackage::getTaskAffinity,
- AndroidPackage::getThemeRes,
+ AndroidPackage::getThemeResourceId,
AndroidPackage::getUiOptions,
AndroidPackage::getUid,
AndroidPackage::getVersionName,
AndroidPackage::getZygotePreloadName,
AndroidPackage::isAllowAudioPlaybackCapture,
- AndroidPackage::isAllowBackup,
- AndroidPackage::isAllowClearUserData,
- AndroidPackage::isAllowClearUserDataOnFailedRestore,
+ AndroidPackage::isBackupAllowed,
+ AndroidPackage::isClearUserDataAllowed,
+ AndroidPackage::isClearUserDataOnFailedRestoreAllowed,
AndroidPackage::isAllowNativeHeapPointerTagging,
- AndroidPackage::isAllowTaskReparenting,
+ AndroidPackage::isTaskReparentingAllowed,
AndroidPackage::isAllowUpdateOwnership,
AndroidPackage::isBackupInForeground,
AndroidPackage::isHardwareAccelerated,
- AndroidPackage::isCantSaveState,
+ AndroidPackage::isSaveStateDisallowed,
AndroidPackage::isCoreApp,
AndroidPackage::isCrossProfile,
AndroidPackage::isDebuggable,
@@ -229,17 +229,17 @@
AndroidPackage::isDirectBootAware,
AndroidPackage::isEnabled,
AndroidPackage::isExternalStorage,
- AndroidPackage::isExtractNativeLibs,
+ AndroidPackage::isExtractNativeLibrariesRequested,
AndroidPackage::isFactoryTest,
AndroidPackage::isApex,
AndroidPackage::isForceQueryable,
AndroidPackage::isFullBackupOnly,
AndroidPackage::isGame,
- AndroidPackage::isHasCode,
+ AndroidPackage::isDeclaredHavingCode,
AndroidPackage::isHasDomainUrls,
- AndroidPackage::isHasFragileUserData,
+ AndroidPackage::isUserDataFragile,
AndroidPackage::isIsolatedSplitLoading,
- AndroidPackage::isKillAfterRestore,
+ AndroidPackage::isKillAfterRestoreAllowed,
AndroidPackage::isLargeHeap,
AndroidPackage::isMultiArch,
AndroidPackage::isNativeLibraryRootRequiresIsa,
@@ -257,12 +257,12 @@
AndroidPackage::isSdkLibrary,
AndroidPackage::isStaticSharedLibrary,
AndroidPackage::isStub,
- AndroidPackage::isSupportsRtl,
+ AndroidPackage::isRtlSupported,
AndroidPackage::isTestOnly,
- AndroidPackage::isUse32BitAbi,
+ AndroidPackage::is32BitAbiPreferred,
AndroidPackage::isUseEmbeddedDex,
- AndroidPackage::isUsesCleartextTraffic,
- AndroidPackage::isUsesNonSdkApi,
+ AndroidPackage::isCleartextTrafficAllowed,
+ AndroidPackage::isNonSdkApiRequested,
AndroidPackage::isVisibleToInstantApps,
AndroidPackage::isVmSafeMode,
AndroidPackage::isLeavingSharedUser,
@@ -282,10 +282,10 @@
getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")),
getter(AndroidPackage::isAnyDensity, false, 0),
getter(AndroidPackage::isResizeable, false, 0),
- getter(AndroidPackage::isSupportsSmallScreens, false, 0),
- getter(AndroidPackage::isSupportsNormalScreens, false, 0),
- getter(AndroidPackage::isSupportsLargeScreens, false, 0),
- getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0),
+ getter(AndroidPackage::isSmallScreensSupported, false, 0),
+ getter(AndroidPackage::isNormalScreensSupported, false, 0),
+ getter(AndroidPackage::isLargeScreensSupported, false, 0),
+ getter(AndroidPackage::isExtraLargeScreensSupported, false, 0),
adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"),
adder(AndroidPackage::getOriginalPackages, "com.test.original"),
adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 8a855e5..5a733c7 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -312,4 +312,4 @@
.that(exception)
.isNotNull()
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index ad224df5..68cfe45 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -223,8 +223,7 @@
private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
BroadcastRecord record, int recordIndex, long enqueueTime) {
- queue.enqueueOrReplaceBroadcast(record, recordIndex,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(record, recordIndex, false);
record.enqueueTime = enqueueTime;
}
@@ -354,8 +353,7 @@
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
queue.setProcessCached(false);
final long notCachedRunnableAt = queue.getRunnableAt();
@@ -377,14 +375,12 @@
// enqueue a bg-priority broadcast then a fg-priority one
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
- queue.enqueueOrReplaceBroadcast(timezoneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, false);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
// verify that:
// (a) the queue is immediately runnable by existence of a fg-priority broadcast
@@ -415,8 +411,7 @@
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 1,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, false);
assertFalse(queue.isRunnable());
assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
@@ -439,8 +434,7 @@
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
mConstants.MAX_PENDING_BROADCASTS = 128;
queue.invalidateRunnableAt();
@@ -466,13 +460,11 @@
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(lazyRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false);
assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);
- queue.enqueueOrReplaceBroadcast(testRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(testRecord, 0, false);
assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
}
@@ -534,26 +526,20 @@
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
queue.enqueueOrReplaceBroadcast(
- makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0,
- null /* replacedBroadcastConsumer */, false);
+ makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
queue.enqueueOrReplaceBroadcast(
- makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0,
- null /* replacedBroadcastConsumer */, false);
+ makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
queue.makeActiveNextPending();
assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index b9893f6..f1acf66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -147,12 +147,12 @@
TEST_PACKAGE_NAME,
1L,
rule.system().dataAppDirectory,
- withPackage = { it.apply { isHasCode = true } })
+ withPackage = { it.apply { isDeclaredHavingCode = true } })
rule.system().stageScanExistingPackage(
TEST_PACKAGE_2_NAME,
1L,
rule.system().dataAppDirectory,
- withPackage = { it.apply { isHasCode = true } })
+ withPackage = { it.apply { isDeclaredHavingCode = true } })
val pm = createPackageManagerService()
rule.system().validateFinalState()
whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 76dfe02..89a5b12 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -708,7 +708,8 @@
public void testStartProfile_fullUserFails() {
setUpUser(TEST_USER_ID1, 0);
assertThrows(IllegalArgumentException.class,
- () -> mUserController.startProfile(TEST_USER_ID1));
+ () -> mUserController.startProfile(TEST_USER_ID1, /* evenWhenDisabled= */ false,
+ /* unlockListener= */ null));
verifyUserNeverAssignedToDisplay();
}
@@ -725,7 +726,8 @@
public void testStartProfile_disabledProfileFails() {
setUpUser(TEST_USER_ID1, UserInfo.FLAG_PROFILE | UserInfo.FLAG_DISABLED, /* preCreated= */
false, UserManager.USER_TYPE_PROFILE_MANAGED);
- assertThat(mUserController.startProfile(TEST_USER_ID1)).isFalse();
+ assertThat(mUserController.startProfile(TEST_USER_ID1, /* evenWhenDisabled=*/ false,
+ /* unlockListener= */ null)).isFalse();
verifyUserNeverAssignedToDisplay();
}
@@ -906,7 +908,8 @@
private void setUpAndStartProfileInBackground(int userId) throws Exception {
setUpUser(userId, UserInfo.FLAG_PROFILE, false, UserManager.USER_TYPE_PROFILE_MANAGED);
- assertThat(mUserController.startProfile(userId)).isTrue();
+ assertThat(mUserController.startProfile(userId, /* evenWhenDisabled=*/ false,
+ /* unlockListener= */ null)).isTrue();
verify(mInjector.mLockPatternUtilsMock, times(1)).unlockUserKeyIfUnsecured(userId);
mUserStates.put(userId, mUserController.getStartedUserState(userId));
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1904671..a616fbc 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -183,6 +183,10 @@
int[] getSupportedHdrOutputTypes() {
return new int[]{};
}
+
+ boolean getHdrOutputConversionSupport() {
+ return false;
+ }
}
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index 704b06b..87aa272 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -24,6 +24,8 @@
import android.app.timedetector.TelephonyTimeSuggestion;
import android.util.IndentingPrintWriter;
+import com.android.server.timezonedetector.StateChangeListener;
+
/**
* A fake implementation of {@link com.android.server.timedetector.TimeDetectorStrategy} for use
* in tests.
@@ -31,6 +33,7 @@
public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
// State
private TimeState mTimeState;
+ private NetworkTimeSuggestion mLatestNetworkTimeSuggestion;
@Override
public TimeState getTimeState() {
@@ -62,8 +65,12 @@
}
@Override
+ public void addNetworkTimeUpdateListener(StateChangeListener networkSuggestionUpdateListener) {
+ }
+
+ @Override
public NetworkTimeSuggestion getLatestNetworkSuggestion() {
- return null;
+ return mLatestNetworkTimeSuggestion;
}
@Override
@@ -81,4 +88,8 @@
@Override
public void dump(IndentingPrintWriter pw, String[] args) {
}
+
+ void setLatestNetworkTime(NetworkTimeSuggestion networkTimeSuggestion) {
+ mLatestNetworkTimeSuggestion = networkTimeSuggestion;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 0b339ad..5a0867f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -54,6 +54,7 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper;
import com.android.server.timezonedetector.TestCallerIdentityInjector;
import com.android.server.timezonedetector.TestHandler;
@@ -420,21 +421,35 @@
@Test
public void testGetLatestNetworkSuggestion() {
- NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
- 1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123));
- when(mMockNtpTrustedTime.getCachedTimeResult())
- .thenReturn(latestNetworkTime);
- UnixEpochTime expectedUnixEpochTime = new UnixEpochTime(
- latestNetworkTime.getElapsedRealtimeMillis(), latestNetworkTime.getTimeMillis());
- NetworkTimeSuggestion expected = new NetworkTimeSuggestion(
- expectedUnixEpochTime, latestNetworkTime.getUncertaintyMillis());
- assertEquals(expected, mTimeDetectorService.getLatestNetworkSuggestion());
+ if (TimeDetectorNetworkTimeHelper.isInUse()) {
+ NetworkTimeSuggestion latestNetworkTime = createNetworkTimeSuggestion();
+ mFakeTimeDetectorStrategySpy.setLatestNetworkTime(latestNetworkTime);
+
+ assertEquals(latestNetworkTime, mTimeDetectorService.getLatestNetworkSuggestion());
+ } else {
+ NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
+ 1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123));
+ when(mMockNtpTrustedTime.getCachedTimeResult())
+ .thenReturn(latestNetworkTime);
+ UnixEpochTime expectedUnixEpochTime = new UnixEpochTime(
+ latestNetworkTime.getElapsedRealtimeMillis(),
+ latestNetworkTime.getTimeMillis());
+ NetworkTimeSuggestion expected = new NetworkTimeSuggestion(
+ expectedUnixEpochTime, latestNetworkTime.getUncertaintyMillis());
+ assertEquals(expected, mTimeDetectorService.getLatestNetworkSuggestion());
+ }
}
@Test
public void testGetLatestNetworkSuggestion_noTimeAvailable() {
- when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
- assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+ if (TimeDetectorNetworkTimeHelper.isInUse()) {
+ mFakeTimeDetectorStrategySpy.setLatestNetworkTime(null);
+
+ assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+ } else {
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
+ assertNull(mTimeDetectorService.getLatestNetworkSuggestion());
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 37da2a2..4df21e0 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -41,6 +41,7 @@
import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.server.timezonedetector.StateChangeListener;
+import com.android.server.timezonedetector.TestStateChangeListener;
import org.junit.Before;
import org.junit.Test;
@@ -51,6 +52,8 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import junitparams.JUnitParamsRunner;
@@ -863,8 +866,11 @@
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_NETWORK)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal)
- .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+ Script script = new Script()
+ .simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -877,6 +883,11 @@
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
@Test
@@ -885,7 +896,10 @@
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setOriginPriorities(ORIGIN_NETWORK)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+ Script script = new Script()
+ .simulateConfigurationInternalChange(configInternal)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -894,6 +908,11 @@
.simulateNetworkTimeSuggestion(timeSuggestion)
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
@Test
@@ -902,7 +921,11 @@
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+ Script script = new Script()
+ .simulateConfigurationInternalChange(configInternal)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
// Create two different time suggestions for the current elapsedRealtimeMillis.
ExternalTimeSuggestion externalTimeSuggestion =
@@ -927,6 +950,11 @@
script.simulateNetworkTimeSuggestion(networkTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
// Clear the network time. This should cause the device to change back to the external time,
@@ -937,6 +965,11 @@
script.simulateClearLatestNetworkSuggestion()
.assertLatestNetworkSuggestion(null)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+
+ // Confirm network time update listeners are asynchronously notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
}
@@ -947,8 +980,11 @@
.setOriginPriorities(ORIGIN_NETWORK)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal)
- .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+ Script script = new Script()
+ .simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
@@ -957,6 +993,11 @@
.assertLatestNetworkSuggestion(null)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Confirm the network time update listener is not notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
}
@Test
@@ -966,8 +1007,10 @@
.setOriginPriorities(ORIGIN_NETWORK)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
Script script = new Script().simulateConfigurationInternalChange(configInternal)
- .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
@@ -976,6 +1019,11 @@
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
@Test
@@ -985,8 +1033,10 @@
.setOriginPriorities(ORIGIN_NETWORK)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
Script script = new Script().simulateConfigurationInternalChange(configInternal)
- .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
@@ -995,6 +1045,11 @@
.assertLatestNetworkSuggestion(null)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Confirm the network time update listener is not notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
}
@Test
@@ -1004,8 +1059,10 @@
.setOriginPriorities(ORIGIN_NETWORK)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
Script script = new Script().simulateConfigurationInternalChange(configInternal)
- .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
@@ -1014,6 +1071,11 @@
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
@Test
@@ -1800,7 +1862,10 @@
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_TELEPHONY)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ TestStateChangeListener networkTimeUpdateListener = new TestStateChangeListener();
+ Script script = new Script()
+ .simulateConfigurationInternalChange(configInternal)
+ .addNetworkTimeUpdateListener(networkTimeUpdateListener);
NetworkTimeSuggestion timeSuggestion = script.generateNetworkTimeSuggestion(
ARBITRARY_TEST_TIME);
@@ -1809,6 +1874,11 @@
.assertLatestNetworkSuggestion(timeSuggestion)
.assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Confirm the network time update listener is notified of a change.
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(0);
+ script.simulateAsyncRunnableExecution();
+ networkTimeUpdateListener.assertNotificationsReceivedAndReset(1);
}
@Test
@@ -1867,6 +1937,8 @@
*/
private static class FakeEnvironment implements TimeDetectorStrategyImpl.Environment {
+ private final List<Runnable> mAsyncRunnables = new ArrayList<>();
+
private ConfigurationInternal mConfigurationInternal;
private boolean mWakeLockAcquired;
private long mElapsedRealtimeMillis;
@@ -1951,8 +2023,20 @@
// No-op for tests
}
+ @Override
+ public void runAsync(Runnable runnable) {
+ mAsyncRunnables.add(runnable);
+ }
+
// Methods below are for managing the fake's behavior.
+ void runAsyncRunnables() {
+ for (Runnable runnable : mAsyncRunnables) {
+ runnable.run();
+ }
+ mAsyncRunnables.clear();
+ }
+
void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
mConfigurationInternal = configurationInternal;
mConfigurationInternalChangeListener.onChange();
@@ -1992,7 +2076,7 @@
assertEquals(expectedSystemClockMillis, mSystemClockMillis);
}
- public void verifySystemClockConfidenceLatest(@TimeConfidence int expectedConfidence) {
+ void verifySystemClockConfidenceLatest(@TimeConfidence int expectedConfidence) {
assertEquals(expectedConfidence, mSystemClockConfidence);
}
@@ -2118,6 +2202,17 @@
return this;
}
+ /** Calls {@link TimeDetectorStrategy#addNetworkTimeUpdateListener(StateChangeListener)}. */
+ Script addNetworkTimeUpdateListener(StateChangeListener listener) {
+ mTimeDetectorStrategy.addNetworkTimeUpdateListener(listener);
+ return this;
+ }
+
+ Script simulateAsyncRunnableExecution() {
+ mFakeEnvironment.runAsyncRunnables();
+ return this;
+ }
+
Script verifySystemClockWasNotSetAndResetCallTracking() {
mFakeEnvironment.verifySystemClockNotSet();
mFakeEnvironment.resetCallTracking();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java
new file mode 100644
index 0000000..9cbf0a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestStateChangeListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 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.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestStateChangeListener implements StateChangeListener {
+
+ private int mNotificationsReceived;
+
+ @Override
+ public void onChange() {
+ mNotificationsReceived++;
+ }
+
+ public void assertNotificationsReceivedAndReset(int expectedCount) {
+ assertNotificationsReceived(expectedCount);
+ resetNotificationsReceivedCount();
+ }
+
+ private void resetNotificationsReceivedCount() {
+ mNotificationsReceived = 0;
+ }
+
+ private void assertNotificationsReceived(int expectedCount) {
+ assertEquals(expectedCount, mNotificationsReceived);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 590aba9..03d406f 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -2001,26 +2001,4 @@
return new TelephonyTestCase(matchType, quality, expectedScore);
}
- private static class TestStateChangeListener implements StateChangeListener {
-
- private int mNotificationsReceived;
-
- @Override
- public void onChange() {
- mNotificationsReceived++;
- }
-
- public void assertNotificationsReceivedAndReset(int expectedCount) {
- assertNotificationsReceived(expectedCount);
- resetNotificationsReceivedCount();
- }
-
- private void resetNotificationsReceivedCount() {
- mNotificationsReceived = 0;
- }
-
- private void assertNotificationsReceived(int expectedCount) {
- assertEquals(expectedCount, mNotificationsReceived);
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index cdbcecc..05ee2f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -704,15 +704,15 @@
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTask(mDisplayContent);
- doReturn(false).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
- doReturn(false).when(oldTask).isTranslucent(any());
+ final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
- opening.setOccludesParent(false);
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -735,8 +735,8 @@
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
- assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) == 0);
- assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
@@ -745,15 +745,15 @@
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTask(mDisplayContent);
- doReturn(true).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
- doReturn(false).when(oldTask).isTranslucent(any());
+ final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
opening.setOccludesParent(false);
+ opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -776,8 +776,186 @@
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
- assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) != 0);
- assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testOpenOpaqueTaskFragment() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testOpenTranslucentTaskFragment() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(false);
+ opening.visibleIgnoringKeyguard = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testCloseOpaqueTaskFragment_withFinishingActivity() {
+ final Transition transition = createTestTransition(TRANSIT_CLOSE);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ closing.finishing = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testCloseTranslucentTaskFragment_withFinishingActivity() {
+ final Transition transition = createTestTransition(TRANSIT_CLOSE);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(false);
+ closing.visibleIgnoringKeyguard = true;
+ closing.finishing = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7404adb..d75e573 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -174,7 +174,7 @@
/**
* Key to the backup & restore data byte array in the Bundle that is returned by {@link
* #getAllSimSpecificSettingsForBackup()} or to be pass in to {@link
- * #restoreAllSimSpecificSettings()}.
+ * #restoreAllSimSpecificSettingsFromBackup(byte[])}.
*
* @hide
*/
@@ -4051,39 +4051,16 @@
}
/**
- * Called to attempt to restore the backed up sim-specific configs to device for specific sim.
- * This will try to restore the data that was stored internally when {@link
- * #restoreAllSimSpecificSettingsFromBackup(byte[] data)} was called during setup wizard.
- * End result is SimInfoDB is modified to match any backed up configs for the requested
- * inserted sim.
- *
- * <p>
- * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
- * entry is updated as the result of this method call.
- *
- * @param iccId of the sim that a restore is requested for.
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void restoreSimSpecificSettingsForIccIdFromBackup(@NonNull String iccId) {
- mContext.getContentResolver().call(
- SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
- RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
- iccId, null);
- }
-
- /**
* Called during setup wizard restore flow to attempt to restore the backed up sim-specific
- * configs to device for all existing SIMs in SimInfoDB. Internally, it will store the backup
- * data in an internal file. This file will persist on device for device's lifetime and will be
- * used later on when a SIM is inserted to restore that specific SIM's settings by calling
- * {@link #restoreSimSpecificSettingsForIccIdFromBackup(String iccId)}. End result is
- * SimInfoDB is modified to match any backed up configs for the appropriate inserted SIMs.
+ * configs to device for all existing SIMs in the subscription database {@link SimInfo}.
+ * Internally, it will store the backup data in an internal file. This file will persist on
+ * device for device's lifetime and will be used later on when a SIM is inserted to restore that
+ * specific SIM's settings. End result is subscription database is modified to match any backed
+ * up configs for the appropriate inserted SIMs.
*
* <p>
- * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
- * entry is updated as the result of this method call.
+ * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+ * {@link SimInfo} entry is updated as the result of this method call.
*
* @param data with the sim specific configs to be backed up.
*
@@ -4092,12 +4069,18 @@
@SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) {
- Bundle bundle = new Bundle();
- bundle.putByteArray(KEY_SIM_SPECIFIC_SETTINGS_DATA, data);
- mContext.getContentResolver().call(
- SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
- RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
- null, bundle);
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ iSub.restoreAllSimSpecificSettingsFromBackup(data);
+ } else {
+ throw new IllegalStateException("subscription service unavailable.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 5f6218d..100799e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1070,6 +1070,45 @@
return SATELLITE_REQUEST_FAILED;
}
+ /**
+ * Send datagram over satellite.
+ * @param datagramType - type of datagram
+ * @param datagram - datagram to send over satellite
+ * @param executor - The executor on which the result listener will be called.
+ * @param resultListener - Listener that will be called with the result of the operation.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void sendSatelliteDatagram(@DatagramType int datagramType,
+ @NonNull SatelliteDatagram datagram, @NonNull @CallbackExecutor Executor executor,
+ @SatelliteError @NonNull Consumer<Integer> resultListener) {
+ Objects.requireNonNull(datagram);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(resultListener);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> resultListener.accept(result)));
+ }
+ };
+ telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
+ internalCallback);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("sendSatelliteDatagram() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
.getTelephonyServiceManager()
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index defa046..af4edc4 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -363,4 +363,20 @@
*/
//TODO: Removed before U AOSP public release.
boolean isSubscriptionManagerServiceEnabled();
+
+ /**
+ * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
+ * configs to device for all existing SIMs in the subscription database
+ * {@link Telephony.SimInfo}. Internally, it will store the backup data in an internal file.
+ * This file will persist on device for device's lifetime and will be used later on when a SIM
+ * is inserted to restore that specific SIM's settings. End result is subscription database is
+ * modified to match any backed up configs for the appropriate inserted SIMs.
+ *
+ * <p>
+ * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+ * {@link Telephony.SimInfo} entry is updated as the result of this method call.
+ *
+ * @param data with the sim specific configs to be backed up.
+ */
+ void restoreAllSimSpecificSettingsFromBackup(in byte[] data);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 331ee6f..9090edb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -69,6 +69,7 @@
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.satellite.ISatelliteStateListener;
import android.telephony.satellite.SatelliteCapabilities;
+import android.telephony.satellite.SatelliteDatagram;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
@@ -2894,4 +2895,17 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
int pollPendingSatelliteDatagrams(int subId);
+
+ /**
+ * Send datagram over satellite.
+ *
+ * @param subId - The subId of the subscription used for receiving datagrams.
+ * @param datagramType - type of datagram
+ * @param datagram - datagram to send over satellite
+ * @param callback - The callback to get the error code of the request.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void sendSatelliteDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+ IIntegerConsumer callback);
}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
index daff76f..5d4a4ef 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -61,10 +61,11 @@
return intent;
}
- protected Intent createBroadcastIntent(String action) {
+ protected Intent createFgBroadcastIntent(String action) {
final Intent intent = new Intent(action);
- intent.addFlags(
- Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
putTimeReceiverBinderExtra(intent);
return intent;
}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
index bc528d4..6a53575 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -30,11 +30,11 @@
@LargeTest
public class BroadcastPerfTest extends BasePerfTest {
@Test
- public void manifestBroadcastRunning() {
+ public void manifestFgBroadcastRunning() {
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -48,9 +48,9 @@
}
@Test
- public void manifestBroadcastNotRunning() {
+ public void manifestFgBroadcastNotRunning() {
runPerfFunction(() -> {
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -64,11 +64,11 @@
}
@Test
- public void registeredBroadcast() {
+ public void registeredFgBroadcast() {
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
final long startTime = System.nanoTime();
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index c298189..8aa369e 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -35,6 +35,8 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.R;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -51,8 +53,6 @@
public class SharedConnectivityManager {
private static final String TAG = SharedConnectivityManager.class.getSimpleName();
private static final boolean DEBUG = true;
- private static final String SERVICE_PACKAGE_NAME = "sharedconnectivity_service_package";
- private static final String SERVICE_CLASS_NAME = "sharedconnectivity_service_class";
private static final class SharedConnectivityCallbackProxy extends
ISharedConnectivityCallback.Stub {
@@ -101,7 +101,7 @@
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
@Override
public void onTetherNetworkConnectionStatusChanged(
@@ -115,7 +115,7 @@
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
@Override
public void onKnownNetworkConnectionStatusChanged(
@@ -129,7 +129,7 @@
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
}
private ISharedConnectivityService mService;
@@ -137,14 +137,33 @@
mProxyMap = new HashMap<>();
/**
- * Constructor for new instance of {@link SharedConnectivityManager}.
+ * Creates a new instance of {@link SharedConnectivityManager}.
*
* Automatically binds to implementation of {@link SharedConnectivityService} specified in
* device overlay.
*
+ * @return An instance of {@link SharedConnectivityManager} or null if the shared connectivity
+ * service is not found.
* @hide
*/
- public SharedConnectivityManager(@NonNull Context context) {
+ @Nullable
+ public static SharedConnectivityManager create(@NonNull Context context) {
+ Resources resources = context.getResources();
+ try {
+ String servicePackageName = resources.getString(
+ R.string.shared_connectivity_service_package);
+ String serviceIntentAction = resources.getString(
+ R.string.shared_connectivity_service_intent_action);
+ return new SharedConnectivityManager(context, servicePackageName, serviceIntentAction);
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "To support shared connectivity service on this device, the service's"
+ + " package name and intent action string must be defined");
+ }
+ return null;
+ }
+
+ private SharedConnectivityManager(@NonNull Context context, String servicePackageName,
+ String serviceIntentAction) {
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -158,7 +177,10 @@
mProxyMap.clear();
}
};
- bind(context, serviceConnection);
+
+ context.bindService(
+ new Intent().setPackage(servicePackageName).setAction(serviceIntentAction),
+ serviceConnection, Context.BIND_AUTO_CREATE);
}
/**
@@ -169,25 +191,6 @@
mService = (ISharedConnectivityService) service;
}
- private void bind(Context context, ServiceConnection serviceConnection) {
- Resources resources = context.getResources();
- int packageNameId = resources.getIdentifier(SERVICE_PACKAGE_NAME, "string",
- context.getPackageName());
- int classNameId = resources.getIdentifier(SERVICE_CLASS_NAME, "string",
- context.getPackageName());
- if (packageNameId == 0 || classNameId == 0) {
- throw new Resources.NotFoundException("Package and class names for"
- + " shared connectivity service must be defined");
- }
-
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(resources.getString(packageNameId),
- resources.getString(classNameId)));
- context.bindService(
- intent,
- serviceConnection, Context.BIND_AUTO_CREATE);
- }
-
/**
* Registers a callback for receiving updates to the list of Tether Networks and Known Networks.
*
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 9aeccac..784e9c4 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -89,7 +89,7 @@
*/
@Test
public void testBindingToService() {
- new SharedConnectivityManager(mContext);
+ SharedConnectivityManager.create(mContext);
verify(mContext).bindService(any(), any(), anyInt());
}
@@ -98,22 +98,22 @@
*/
@Test
public void testRegisterCallback() throws Exception {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
assertTrue(manager.registerCallback(mExecutor, mClientCallback));
verify(mService).registerCallback(any());
// Registering the same callback twice should fail.
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).registerCallback(any());
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
@@ -125,24 +125,24 @@
*/
@Test
public void testUnregisterCallback() throws Exception {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.unregisterCallback(mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertTrue(manager.unregisterCallback(mClientCallback));
verify(mService).unregisterCallback(any());
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
manager.unregisterCallback(mClientCallback);
assertFalse(manager.unregisterCallback(mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).unregisterCallback(any());
assertFalse(manager.unregisterCallback(mClientCallback));
@@ -156,11 +156,11 @@
public void testConnectTetherNetwork() throws RemoteException {
TetherNetwork network = buildTetherNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectTetherNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectTetherNetwork(network);
verify(mService).connectTetherNetwork(network);
@@ -175,11 +175,11 @@
*/
@Test
public void testDisconnectTetherNetwork() throws RemoteException {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.disconnectTetherNetwork());
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.disconnectTetherNetwork();
verify(mService).disconnectTetherNetwork();
@@ -196,11 +196,11 @@
public void testConnectKnownNetwork() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectKnownNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectKnownNetwork(network);
verify(mService).connectKnownNetwork(network);
@@ -217,11 +217,11 @@
public void testForgetKnownNetwork() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.forgetKnownNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.forgetKnownNetwork(network);
verify(mService).forgetKnownNetwork(network);