Merge "Added network objects to ConnectionStatus classes."
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/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 1022490..bd8d27c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -27,6 +27,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.BackgroundStartPrivileges;
import android.app.UserSwitchObserver;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -388,6 +389,12 @@
private final ArrayList<ContextAssignment> mRecycledPreferredUidOnly = new ArrayList<>();
private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>();
private final AssignmentInfo mRecycledAssignmentInfo = new AssignmentInfo();
+ private final SparseIntArray mRecycledPrivilegedState = new SparseIntArray();
+
+ private static final int PRIVILEGED_STATE_UNDEFINED = 0;
+ private static final int PRIVILEGED_STATE_NONE = 1;
+ private static final int PRIVILEGED_STATE_BAL = 2;
+ private static final int PRIVILEGED_STATE_TOP = 3;
private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
@@ -792,7 +799,7 @@
cleanUpAfterAssignmentChangesLocked(
mRecycledChanged, mRecycledIdle, mRecycledPreferredUidOnly, mRecycledStoppable,
- mRecycledAssignmentInfo);
+ mRecycledAssignmentInfo, mRecycledPrivilegedState);
noteConcurrency();
}
@@ -915,7 +922,8 @@
continue;
}
- final boolean hasImmediacyPrivilege = hasImmediacyPrivilegeLocked(nextPending);
+ final boolean hasImmediacyPrivilege =
+ hasImmediacyPrivilegeLocked(nextPending, mRecycledPrivilegedState);
if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
Slog.w(TAG, "Already running similar job to: " + nextPending);
}
@@ -1183,7 +1191,8 @@
final ArraySet<ContextAssignment> idle,
final List<ContextAssignment> preferredUidOnly,
final List<ContextAssignment> stoppable,
- final AssignmentInfo assignmentInfo) {
+ final AssignmentInfo assignmentInfo,
+ final SparseIntArray privilegedState) {
for (int s = stoppable.size() - 1; s >= 0; --s) {
final ContextAssignment assignment = stoppable.get(s);
assignment.clear();
@@ -1205,20 +1214,58 @@
stoppable.clear();
preferredUidOnly.clear();
assignmentInfo.clear();
+ privilegedState.clear();
mWorkCountTracker.resetStagingCount();
mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
}
@VisibleForTesting
@GuardedBy("mLock")
- boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job) {
+ boolean hasImmediacyPrivilegeLocked(@NonNull JobStatus job,
+ @NonNull SparseIntArray cachedPrivilegedState) {
+ if (!job.shouldTreatAsExpeditedJob() && !job.shouldTreatAsUserInitiatedJob()) {
+ return false;
+ }
// EJs & user-initiated jobs for the TOP app should run immediately.
// However, even for user-initiated jobs, if the app has not recently been in TOP or BAL
// state, we don't give the immediacy privilege so that we can try and maintain
// reasonably concurrency behavior.
- return job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP
- // TODO(): include BAL state for user-initiated jobs
- && (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob());
+ if (job.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
+ return true;
+ }
+ final int uid = job.getSourceUid();
+ final int privilegedState = cachedPrivilegedState.get(uid, PRIVILEGED_STATE_UNDEFINED);
+ switch (privilegedState) {
+ case PRIVILEGED_STATE_TOP:
+ return true;
+ case PRIVILEGED_STATE_BAL:
+ return job.shouldTreatAsUserInitiatedJob();
+ case PRIVILEGED_STATE_NONE:
+ return false;
+ case PRIVILEGED_STATE_UNDEFINED:
+ default:
+ final ActivityManagerInternal activityManagerInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+ final int procState = activityManagerInternal.getUidProcessState(uid);
+ if (procState == ActivityManager.PROCESS_STATE_TOP) {
+ cachedPrivilegedState.put(uid, PRIVILEGED_STATE_TOP);
+ return true;
+ }
+ if (job.shouldTreatAsExpeditedJob()) {
+ // EJs only get the TOP privilege.
+ return false;
+ }
+
+ final BackgroundStartPrivileges bsp =
+ activityManagerInternal.getBackgroundStartPrivileges(uid);
+ final boolean balAllowed = bsp.allowsBackgroundActivityStarts();
+ if (DEBUG) {
+ Slog.d(TAG, "Job " + job.toShortString() + " bal state: " + bsp);
+ }
+ cachedPrivilegedState.put(uid,
+ balAllowed ? PRIVILEGED_STATE_BAL : PRIVILEGED_STATE_NONE);
+ return balAllowed;
+ }
}
@GuardedBy("mLock")
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 419111a..22fea7f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -31,6 +31,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
+import android.app.BackgroundStartPrivileges;
import android.app.IUidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
@@ -3841,6 +3842,25 @@
return callingResult;
}
}
+
+ final int uid = sourceUid != -1 ? sourceUid : callingUid;
+ final int procState = mActivityManagerInternal.getUidProcessState(uid);
+ if (DEBUG) {
+ Slog.d(TAG, "Uid " + uid + " proc state="
+ + ActivityManager.procStateToString(procState));
+ }
+ if (procState != ActivityManager.PROCESS_STATE_TOP) {
+ final BackgroundStartPrivileges bsp =
+ mActivityManagerInternal.getBackgroundStartPrivileges(uid);
+ if (DEBUG) {
+ Slog.d(TAG, "Uid " + uid + ": " + bsp);
+ }
+ if (!bsp.allowsBackgroundActivityStarts()) {
+ Slog.e(TAG,
+ "Uid " + uid + " not in a state to schedule user-initiated jobs");
+ return JobScheduler.RESULT_FAILURE;
+ }
+ }
}
if (jobWorkItem != null) {
jobWorkItem.enforceValidity(rejectNegativeNetworkEstimates);
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 1a8166b..7ed066e 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
@@ -7750,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);
@@ -7757,6 +7782,7 @@
method public int addOverrideApn(@NonNull android.content.ComponentName, @NonNull android.telephony.data.ApnSetting);
method public void addPersistentPreferredActivity(@NonNull android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
method public void addUserRestriction(@NonNull android.content.ComponentName, String);
+ method public void addUserRestrictionGlobally(@NonNull String);
method public boolean bindDeviceAdminServiceAsUser(@NonNull android.content.ComponentName, android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
method public boolean canAdminGrantSensorsPermissions();
method public boolean canUsbDataSignalingBeDisabled();
@@ -7859,6 +7885,7 @@
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
method @NonNull public java.util.List<java.lang.String> getUserControlDisabledPackages(@NonNull android.content.ComponentName);
method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
+ method @NonNull public android.os.Bundle getUserRestrictionsGlobally();
method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
method @Nullable public android.app.admin.WifiSsidPolicy getWifiSsidPolicy();
method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
@@ -7901,6 +7928,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();
@@ -7935,7 +7963,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);
@@ -8141,6 +8169,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
@@ -8302,6 +8331,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
@@ -8314,6 +8345,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";
@@ -14903,6 +14935,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();
@@ -14918,6 +14951,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();
@@ -14929,6 +14963,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);
@@ -15464,6 +15499,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();
@@ -27363,6 +27418,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();
@@ -27651,8 +27707,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);
@@ -27687,8 +27748,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();
@@ -27729,7 +27792,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);
@@ -27783,8 +27847,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);
@@ -33394,6 +33460,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
@@ -41386,9 +41453,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";
}
@@ -53721,12 +53790,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);
@@ -53737,6 +53808,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/system-current.txt b/core/api/system-current.txt
index 2d7be50..ba9663f 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";
@@ -1205,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;
}
@@ -1290,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";
@@ -1393,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();
@@ -1521,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;
@@ -1541,10 +1554,18 @@
}
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;
}
+ public final class UserRestrictionPolicyKey extends android.app.admin.PolicyKey {
+ method public int describeContents();
+ method @NonNull public String getRestriction();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UserRestrictionPolicyKey> CREATOR;
+ }
+
}
package android.app.ambientcontext {
@@ -2262,7 +2283,6 @@
method public void notifyEvent(@NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent);
method @Nullable public void query(@NonNull android.app.search.Query, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>);
method public void registerEmptyQueryResultUpdateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.search.SearchSession.Callback);
- method public void requestEmptyQueryResultUpdate();
method public void unregisterEmptyQueryResultUpdateCallback(@NonNull android.app.search.SearchSession.Callback);
}
@@ -10651,7 +10671,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";
@@ -12675,7 +12694,6 @@
method @MainThread public abstract void onDestroy(@NonNull android.app.search.SearchSessionId);
method @MainThread public abstract void onNotifyEvent(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull android.app.search.SearchTargetEvent);
method @MainThread public abstract void onQuery(@NonNull android.app.search.SearchSessionId, @NonNull android.app.search.Query, @NonNull java.util.function.Consumer<java.util.List<android.app.search.SearchTarget>>);
- method @MainThread public void onRequestEmptyQueryResultUpdate(@NonNull android.app.search.SearchSessionId);
method public void onSearchSessionCreated(@NonNull android.app.search.SearchContext, @NonNull android.app.search.SearchSessionId);
method @MainThread public void onStartUpdateEmptyQueryResult();
method @MainThread public void onStopUpdateEmptyQueryResult();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f310d8d..bb3ea7b 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);
@@ -1479,10 +1497,13 @@
method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void removeKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
method public void removeUniqueIdAssociation(@NonNull String);
method @RequiresPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT) public void setCurrentKeyboardLayoutForInputDevice(@NonNull android.hardware.input.InputDeviceIdentifier, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setMaximumObscuringOpacityForTouch(@FloatRange(from=0, to=1) float);
field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
}
+ public class InputSettings {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void setMaximumObscuringOpacityForTouch(@NonNull android.content.Context, @FloatRange(from=0, to=1) float);
+ }
+
}
package android.hardware.lights {
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/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0fa1a37..aa9212f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -464,6 +464,11 @@
public abstract boolean isActivityStartsLoggingEnabled();
/** Returns true if the background activity starts is enabled. */
public abstract boolean isBackgroundActivityStartsEnabled();
+ /**
+ * Returns The current {@link BackgroundStartPrivileges} of the UID.
+ */
+ @NonNull
+ public abstract BackgroundStartPrivileges getBackgroundStartPrivileges(int uid);
public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);
/** @see com.android.server.am.ActivityManagerService#monitor */
@@ -963,4 +968,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/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 a2c4820..29d80f8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -95,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,
@@ -487,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
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..4016e32 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}
*/
@@ -11300,6 +11269,13 @@
* See the constants in {@link android.os.UserManager} for the list of restrictions that can
* be enforced device-wide.
*
+ * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+ * above, calling this API will result in applying the restriction locally on the calling user,
+ * or locally on the parent profile if called from the
+ * {@link DevicePolicyManager} instance obtained from
+ * {@link #getParentProfileInstance(ComponentName)}. To set a restriction globally, call
+ * {@link #addUserRestrictionGlobally} instead.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param key The key of the restriction.
* @throws SecurityException if {@code admin} is not a device or profile owner.
@@ -11308,7 +11284,38 @@
@UserManager.UserRestrictionKey String key) {
if (mService != null) {
try {
- mService.setUserRestriction(admin, key, true, mParentInstance);
+ mService.setUserRestriction(
+ admin, mContext.getPackageName(), key, true, mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Called by a profile or device owner to set a user restriction specified by the provided
+ * {@code key} globally on all users. To clear the restriction use
+ * {@link #clearUserRestriction}.
+ *
+ * <p>For a given user, a restriction will be set if it was applied globally or locally by any
+ * admin.
+ *
+ * <p> The calling device admin must be a profile or device owner; if it is not, a security
+ * exception will be thrown.
+ *
+ * <p> See the constants in {@link android.os.UserManager} for the list of restrictions that can
+ * be enforced device-wide.
+ *
+ * @param key The key of the restriction.
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws IllegalStateException if caller is not targeting Android
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
+ */
+ public void addUserRestrictionGlobally(@NonNull @UserManager.UserRestrictionKey String key) {
+ throwIfParentInstance("addUserRestrictionGlobally");
+ if (mService != null) {
+ try {
+ mService.setUserRestrictionGlobally(mContext.getPackageName(), key);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11327,6 +11334,10 @@
* <p>
* See the constants in {@link android.os.UserManager} for the list of restrictions.
*
+ * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+ * above, calling this API will result in clearing any local and global restriction with the
+ * specified key that was previously set by the caller.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param key The key of the restriction.
* @throws SecurityException if {@code admin} is not a device or profile owner.
@@ -11335,7 +11346,8 @@
@UserManager.UserRestrictionKey String key) {
if (mService != null) {
try {
- mService.setUserRestriction(admin, key, false, mParentInstance);
+ mService.setUserRestriction(
+ admin, mContext.getPackageName(), key, false, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11355,6 +11367,18 @@
* {@link #getParentProfileInstance(ComponentName)}, for retrieving device-wide restrictions
* it previously set with {@link #addUserRestriction(ComponentName, String)}.
*
+ * <p>For callers targeting Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or
+ * above, this API will return the local restrictions set on the calling user, or on the parent
+ * profile if called from the {@link DevicePolicyManager} instance obtained from
+ * {@link #getParentProfileInstance(ComponentName)}. To get global restrictions set by admin,
+ * call {@link #getUserRestrictionsGlobally()} instead.
+ *
+ * <p>Note that this is different that the returned restrictions for callers targeting pre
+ * Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, were this API returns
+ * all local/global restrictions set by the admin on the calling user using
+ * {@link #addUserRestriction(ComponentName, String)} or the parent user if called on the
+ * {@link DevicePolicyManager} instance it obtained from {@link #getParentProfileInstance}.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return a {@link Bundle} whose keys are the user restrictions, and the values a
* {@code boolean} indicating whether the restriction is set.
@@ -11364,7 +11388,33 @@
Bundle ret = null;
if (mService != null) {
try {
- ret = mService.getUserRestrictions(admin, mParentInstance);
+ ret = mService.getUserRestrictions(
+ admin, mContext.getPackageName(), mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return ret == null ? new Bundle() : ret;
+ }
+
+ /**
+ * Called by a profile or device owner to get global user restrictions set with
+ * {@link #addUserRestrictionGlobally(String)}.
+ * <p>
+ * To get all the user restrictions currently set for a certain user, use
+ * {@link UserManager#getUserRestrictions()}.
+ * @return a {@link Bundle} whose keys are the user restrictions, and the values a
+ * {@code boolean} indicating whether the restriction is set.
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws IllegalStateException if caller is not targeting Android
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
+ */
+ public @NonNull Bundle getUserRestrictionsGlobally() {
+ throwIfParentInstance("createAdminSupportIntent");
+ Bundle ret = null;
+ if (mService != null) {
+ try {
+ ret = mService.getUserRestrictionsGlobally(mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -12586,6 +12636,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..5b9e948 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);
@@ -247,8 +247,11 @@
void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
ComponentName getRestrictionsProvider(int userHandle);
- void setUserRestriction(in ComponentName who, in String key, boolean enable, boolean parent);
- Bundle getUserRestrictions(in ComponentName who, boolean parent);
+ void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
+ void setUserRestrictionGlobally(in String callerPackage, in String key);
+ Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
+ Bundle getUserRestrictionsGlobally(in String callerPackage);
+
void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearCrossProfileIntentFilters(in ComponentName admin);
@@ -379,6 +382,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..a49152d 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -18,6 +18,7 @@
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_INTENT_FILTER;
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;
@@ -100,7 +101,7 @@
*/
@Override
public void writeToBundle(Bundle bundle) {
- super.writeToBundle(bundle);
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
Bundle extraPolicyParams = new Bundle();
extraPolicyParams.putParcelable(EXTRA_INTENT_FILTER, mFilter);
bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
@@ -117,7 +118,7 @@
@Override
public int hashCode() {
- return Objects.hash(getIdentifier(), mFilter);
+ return Objects.hash(getIdentifier());
}
@Override
@@ -133,7 +134,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/NoArgsPolicyKey.java b/core/java/android/app/admin/NoArgsPolicyKey.java
index 57b67d5..2c9d2be 100644
--- a/core/java/android/app/admin/NoArgsPolicyKey.java
+++ b/core/java/android/app/admin/NoArgsPolicyKey.java
@@ -16,8 +16,11 @@
package android.app.admin;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,6 +44,14 @@
this(source.readString());
}
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToBundle(Bundle bundle) {
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 4aa2e38..90ca052 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -19,6 +19,7 @@
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PERMISSION_NAME;
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;
@@ -119,7 +120,7 @@
*/
@Override
public void writeToBundle(Bundle bundle) {
- super.writeToBundle(bundle);
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
Bundle extraPolicyParams = new Bundle();
extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
extraPolicyParams.putString(EXTRA_PERMISSION_NAME, mPermissionName);
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index 3469970..08b6110 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -18,6 +18,7 @@
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_PACKAGE_NAME;
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;
@@ -101,7 +102,7 @@
*/
@Override
public void writeToBundle(Bundle bundle) {
- super.writeToBundle(bundle);
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
Bundle extraPolicyParams = new Bundle();
extraPolicyParams.putString(EXTRA_PACKAGE_NAME, mPackageName);
bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
diff --git a/core/java/android/app/admin/PolicyKey.java b/core/java/android/app/admin/PolicyKey.java
index a35f634..3544c19 100644
--- a/core/java/android/app/admin/PolicyKey.java
+++ b/core/java/android/app/admin/PolicyKey.java
@@ -16,8 +16,6 @@
package android.app.admin;
-import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -39,8 +37,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 {
@@ -104,9 +101,7 @@
/**
* @hide
*/
- public void writeToBundle(Bundle bundle) {
- bundle.putString(EXTRA_POLICY_KEY, mIdentifier);
- }
+ public abstract void writeToBundle(Bundle bundle);
@Override
public boolean equals(@Nullable Object o) {
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/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
new file mode 100644
index 0000000..92014763
--- /dev/null
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -0,0 +1,97 @@
+/*
+ * 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_POLICY_KEY;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain user restriction
+ * (See {@link DevicePolicyManager#addUserRestriction} and
+ * {@link DevicePolicyManager#addUserRestrictionGlobally}).
+ *
+ * @hide
+ */
+@SystemApi
+public final class UserRestrictionPolicyKey extends PolicyKey {
+
+ private final String mRestriction;
+
+ /**
+ * @hide
+ */
+ public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
+ super(identifier);
+ mRestriction = Objects.requireNonNull(restriction);
+ }
+
+ private UserRestrictionPolicyKey(Parcel source) {
+ this(source.readString(), source.readString());
+ }
+
+ /**
+ * Returns the user restriction associated with this policy.
+ */
+ @NonNull
+ public String getRestriction() {
+ return mRestriction;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToBundle(Bundle bundle) {
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getIdentifier());
+ dest.writeString(mRestriction);
+ }
+
+ @NonNull
+ public static final Creator<UserRestrictionPolicyKey> CREATOR =
+ new Creator<UserRestrictionPolicyKey>() {
+ @Override
+ public UserRestrictionPolicyKey createFromParcel(Parcel source) {
+ return new UserRestrictionPolicyKey(source);
+ }
+
+ @Override
+ public UserRestrictionPolicyKey[] newArray(int size) {
+ return new UserRestrictionPolicyKey[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "UserRestrictionPolicyKey " + getIdentifier();
+ }
+}
diff --git a/core/java/android/app/search/ISearchUiManager.aidl b/core/java/android/app/search/ISearchUiManager.aidl
index fefbd5a..4cf0b81 100644
--- a/core/java/android/app/search/ISearchUiManager.aidl
+++ b/core/java/android/app/search/ISearchUiManager.aidl
@@ -38,8 +38,6 @@
void registerEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
- void requestEmptyQueryResultUpdate(in SearchSessionId sessionId);
-
void unregisterEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
void destroySearchSession(in SearchSessionId sessionId);
diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java
index 9e0a1d0..0dbd81e 100644
--- a/core/java/android/app/search/SearchSession.java
+++ b/core/java/android/app/search/SearchSession.java
@@ -225,32 +225,6 @@
}
/**
- * Requests the search ui service to dispatch a new set of search targets to the pre-registered
- * callback for zero state. Zero state means when user entered search ui but not issued any
- * query yet. This method can be used for client to sync up with server data if they think data
- * might be out of sync, for example, after restart.
- * Pre-register a callback with
- * {@link SearchSession#registerEmptyQueryResultUpdateCallback(Executor, Callback)}
- * is required before calling this method. Otherwise this is no-op.
- *
- * @see {@link SearchSession#registerEmptyQueryResultUpdateCallback(Executor, Callback)}
- * @see {@link SearchSession.Callback#onTargetsAvailable(List)}.
- */
- public void requestEmptyQueryResultUpdate() {
- if (mIsClosed.get()) {
- throw new IllegalStateException("This client has already been destroyed.");
- }
-
- try {
- mInterface.requestEmptyQueryResultUpdate(mSessionId);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to request empty query result update", e);
- e.rethrowAsRuntimeException();
- }
- }
-
-
- /**
* Destroys the client and unregisters the callback. Any method on this class after this call
* will throw {@link IllegalStateException}.
*
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/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 709fa60..41c406d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -614,8 +614,15 @@
boolean status = true;
synchronized (mInterfaceLock) {
try {
- mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
- mInitialized = true;
+ if (mSessionProcessor != null) {
+ mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
+ mInitialized = true;
+ } else {
+ Log.v(TAG, "Failed to start capture session, session released before " +
+ "extension start!");
+ status = false;
+ mCaptureSession.close();
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to start capture session,"
+ " extension service does not respond!");
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7164dc3..067d0c5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -541,7 +541,8 @@
EVENT_FLAG_DISPLAY_ADDED,
EVENT_FLAG_DISPLAY_CHANGED,
EVENT_FLAG_DISPLAY_REMOVED,
- EVENT_FLAG_DISPLAY_BRIGHTNESS
+ EVENT_FLAG_DISPLAY_BRIGHTNESS,
+ EVENT_FLAG_HDR_SDR_RATIO_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventsMask {}
@@ -584,6 +585,19 @@
*/
public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3;
+ /**
+ * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent
+ * through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr
+ * values can be retrieved via {@link Display#getHdrSdrRatio()}.
+ *
+ * Requires that {@link Display#isHdrSdrRatioAvailable()} is true.
+ *
+ * @see #registerDisplayListener(DisplayListener, Handler, long)
+ *
+ * @hide
+ */
+ public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4;
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
@@ -1429,6 +1443,7 @@
* hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}.
*
* @see #getHdrConversionMode
+ * @see #getHdrConversionModeSetting
* @see #getSupportedHdrOutputTypes
* @hide
*/
@@ -1440,9 +1455,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 +1472,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..f419ae4 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -38,6 +38,7 @@
import android.media.projection.IMediaProjection;
import android.media.projection.MediaProjection;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -56,11 +57,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Manager communication with the display manager service on behalf of
@@ -82,11 +84,12 @@
// orientation change before the display info cache has actually been invalidated.
private static final boolean USE_CACHE = false;
- @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
+ @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = {
EVENT_DISPLAY_ADDED,
EVENT_DISPLAY_CHANGED,
EVENT_DISPLAY_REMOVED,
- EVENT_DISPLAY_BRIGHTNESS_CHANGED
+ EVENT_DISPLAY_BRIGHTNESS_CHANGED,
+ EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayEvent {}
@@ -95,6 +98,7 @@
public static final int EVENT_DISPLAY_CHANGED = 2;
public static final int EVENT_DISPLAY_REMOVED = 3;
public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4;
+ public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5;
@UnsupportedAppUsage
private static DisplayManagerGlobal sInstance;
@@ -109,7 +113,8 @@
private DisplayManagerCallback mCallback;
private @EventsMask long mRegisteredEventsMask = 0;
- private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>();
+ private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners =
+ new CopyOnWriteArrayList<>();
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();
private final ColorSpace mWideColorSpace;
@@ -315,6 +320,19 @@
*/
public void registerDisplayListener(@NonNull DisplayListener listener,
@Nullable Handler handler, @EventsMask long eventsMask) {
+ Looper looper = getLooperForHandler(handler);
+ Handler springBoard = new Handler(looper);
+ registerDisplayListener(listener, new HandlerExecutor(springBoard), eventsMask);
+ }
+
+ /**
+ * Register a listener for display-related changes.
+ *
+ * @param listener The listener that will be called when display changes occur.
+ * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null.
+ */
+ public void registerDisplayListener(@NonNull DisplayListener listener,
+ @NonNull Executor executor, @EventsMask long eventsMask) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
@@ -326,8 +344,7 @@
synchronized (mLock) {
int index = findDisplayListenerLocked(listener);
if (index < 0) {
- Looper looper = getLooperForHandler(handler);
- mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));
+ mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, eventsMask));
registerCallbackIfNeededLocked();
} else {
mDisplayListeners.get(index).setEventsMask(eventsMask);
@@ -408,6 +425,7 @@
}
private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
+ final DisplayInfo info;
synchronized (mLock) {
if (USE_CACHE) {
mDisplayInfoCache.remove(displayId);
@@ -417,11 +435,7 @@
}
}
- final int numListeners = mDisplayListeners.size();
- DisplayInfo info = getDisplayInfo(displayId);
- for (int i = 0; i < numListeners; i++) {
- mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info);
- }
+ info = getDisplayInfoLocked(displayId);
if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) {
// Choreographer only supports a single display, so only dispatch refresh rate
// changes for the default display.
@@ -438,6 +452,11 @@
}
}
}
+ // Accepting an Executor means the listener may be synchronously invoked, so we must
+ // not be holding mLock when we do so
+ for (DisplayListenerDelegate listener : mDisplayListeners) {
+ listener.sendDisplayEvent(displayId, event, info);
+ }
}
public void startWifiDisplayScan() {
@@ -990,6 +1009,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() {
@@ -1075,34 +1107,42 @@
}
}
- private static final class DisplayListenerDelegate extends Handler {
+ private static final class DisplayListenerDelegate {
public final DisplayListener mListener;
public volatile long mEventsMask;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
+ private final Executor mExecutor;
+ private AtomicLong mGenerationId = new AtomicLong(1);
- DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
+ DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor,
@EventsMask long eventsMask) {
- super(looper, null, true /*async*/);
+ mExecutor = executor;
mListener = listener;
mEventsMask = eventsMask;
}
public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) {
- Message msg = obtainMessage(event, displayId, 0, info);
- sendMessage(msg);
+ long generationId = mGenerationId.get();
+ Message msg = Message.obtain(null, event, displayId, 0, info);
+ mExecutor.execute(() -> {
+ // If the generation id's don't match we were canceled but still need to recycle()
+ if (generationId == mGenerationId.get()) {
+ handleMessage(msg);
+ }
+ msg.recycle();
+ });
}
public void clearEvents() {
- removeCallbacksAndMessages(null);
+ mGenerationId.incrementAndGet();
}
public void setEventsMask(@EventsMask long newEventsMask) {
mEventsMask = newEventsMask;
}
- @Override
- public void handleMessage(Message msg) {
+ private void handleMessage(Message msg) {
if (DEBUG) {
Trace.beginSection(
"DisplayListenerDelegate(" + eventToString(msg.what)
@@ -1134,6 +1174,11 @@
mListener.onDisplayRemoved(msg.arg1);
}
break;
+ case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+ if ((mEventsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) {
+ mListener.onDisplayChanged(msg.arg1);
+ }
+ break;
}
if (DEBUG) {
Trace.endSection();
@@ -1255,6 +1300,8 @@
return "REMOVED";
case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
return "BRIGHTNESS_CHANGED";
+ case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+ return "HDR_SDR_RATIO_CHANGED";
}
return "UNKNOWN";
}
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/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 657541c..2ea9ea0 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -51,11 +51,9 @@
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
-import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -215,30 +213,6 @@
"android.hardware.input.metadata.KEYBOARD_LAYOUTS";
/**
- * Pointer Speed: The minimum (slowest) pointer speed (-7).
- * @hide
- */
- public static final int MIN_POINTER_SPEED = -7;
-
- /**
- * Pointer Speed: The maximum (fastest) pointer speed (7).
- * @hide
- */
- public static final int MAX_POINTER_SPEED = 7;
-
- /**
- * Pointer Speed: The default pointer speed (0).
- * @hide
- */
- public static final int DEFAULT_POINTER_SPEED = 0;
-
- /**
- * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1).
- * @hide
- */
- public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f;
-
- /**
* Prevent touches from being consumed by apps if these touches passed through a non-trusted
* window from a different UID and are considered unsafe.
*
@@ -1135,58 +1109,18 @@
}
/**
- * Gets the mouse pointer speed.
- * <p>
- * Only returns the permanent mouse pointer speed. Ignores any temporary pointer
- * speed set by {@link #tryPointerSpeed}.
- * </p>
- *
- * @param context The application context.
- * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
- * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
- *
- * @hide
- */
- public int getPointerSpeed(Context context) {
- return Settings.System.getInt(context.getContentResolver(),
- Settings.System.POINTER_SPEED, DEFAULT_POINTER_SPEED);
- }
-
- /**
- * Sets the mouse pointer speed.
- * <p>
- * Requires {@link android.Manifest.permission#WRITE_SETTINGS}.
- * </p>
- *
- * @param context The application context.
- * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
- * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public void setPointerSpeed(Context context, int speed) {
- if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
- throw new IllegalArgumentException("speed out of range");
- }
-
- Settings.System.putInt(context.getContentResolver(),
- Settings.System.POINTER_SPEED, speed);
- }
-
- /**
* Changes the mouse pointer speed temporarily, but does not save the setting.
* <p>
* Requires {@link android.Manifest.permission#SET_POINTER_SPEED}.
* </p>
*
- * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
- * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ * @param speed The pointer speed as a value between {@link InputSettings#MIN_POINTER_SPEED} and
+ * {@link InputSettings#MAX_POINTER_SPEED}, or the default value {@link InputSettings#DEFAULT_POINTER_SPEED}.
*
* @hide
*/
public void tryPointerSpeed(int speed) {
- if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ if (speed < InputSettings.MIN_POINTER_SPEED || speed > InputSettings.MAX_POINTER_SPEED) {
throw new IllegalArgumentException("speed out of range");
}
@@ -1211,44 +1145,8 @@
*/
@FloatRange(from = 0, to = 1)
public float getMaximumObscuringOpacityForTouch() {
- return Settings.Global.getFloat(getContext().getContentResolver(),
- Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
- DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
- }
-
- /**
- * Sets the maximum allowed obscuring opacity by UID to propagate touches.
- *
- * <p>For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams
- * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows
- * above the touch-consuming window.
- *
- * <p>For a certain UID:
- * <ul>
- * <li>If it's the same as the UID of the touch-consuming window, allow it to propagate
- * the touch.
- * <li>Otherwise take all its windows of eligible window types above the touch-consuming
- * window, compute their combined obscuring opacity considering that {@code
- * opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is
- * lesser than or equal to this setting and there are no other windows preventing the
- * touch, allow the UID to propagate the touch.
- * </ul>
- *
- * <p>This value should be between 0 (inclusive) and 1 (inclusive).
- *
- * @see #getMaximumObscuringOpacityForTouch()
- *
- * @hide
- */
- @TestApi
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public void setMaximumObscuringOpacityForTouch(@FloatRange(from = 0, to = 1) float opacity) {
- if (opacity < 0 || opacity > 1) {
- throw new IllegalArgumentException(
- "Maximum obscuring opacity for touch should be >= 0 and <= 1");
- }
- Settings.Global.putFloat(getContext().getContentResolver(),
- Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity);
+ Context context = ActivityThread.currentApplication();
+ return InputSettings.getMaximumObscuringOpacityForTouch(context);
}
/**
@@ -2145,26 +2043,6 @@
}
/**
- * Whether stylus has ever been used on device (false by default).
- * @hide
- */
- public boolean isStylusEverUsed(@NonNull Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.STYLUS_EVER_USED, 0) == 1;
- }
-
- /**
- * Set whether stylus has ever been used on device.
- * Should only ever be set to true once after stylus first usage.
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public void setStylusEverUsed(@NonNull Context context, boolean stylusEverUsed) {
- Settings.Global.putInt(context.getContentResolver(),
- Settings.Global.STYLUS_EVER_USED, stylusEverUsed ? 1 : 0);
- }
-
- /**
* Whether there is a gesture-compatible touchpad connected to the device.
* @hide
*/
@@ -2174,200 +2052,6 @@
}
/**
- * Gets the touchpad pointer speed.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
- * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
- *
- * @hide
- */
- public int getTouchpadPointerSpeed(@NonNull Context context) {
- return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_POINTER_SPEED, DEFAULT_POINTER_SPEED,
- UserHandle.USER_CURRENT);
- }
-
- /**
- * Sets the touchpad pointer speed, and saves it in the settings.
- *
- * The new speed will only apply to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
- * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public void setTouchpadPointerSpeed(@NonNull Context context, int speed) {
- if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
- throw new IllegalArgumentException("speed out of range");
- }
-
- Settings.System.putIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_POINTER_SPEED, speed, UserHandle.USER_CURRENT);
- }
-
- /**
- * Returns true if the touchpad should use pointer acceleration.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return Whether the touchpad should use pointer acceleration.
- *
- * @hide
- */
- public boolean useTouchpadPointerAcceleration(@NonNull Context context) {
- // TODO: obtain the actual behavior from the settings
- return true;
- }
-
- /**
- * Sets the pointer acceleration behavior for the touchpad.
- *
- * The new behavior is only applied to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @param enabled Will enable pointer acceleration if true, disable it if false
- *
- * @hide
- */
- public void setTouchpadPointerAcceleration(@NonNull Context context, boolean enabled) {
- // TODO: set the right setting
- }
-
- /**
- * Returns true if moving two fingers upwards on the touchpad should
- * scroll down, which is known as natural scrolling.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return Whether the touchpad should use natural scrolling.
- *
- * @hide
- */
- public boolean useTouchpadNaturalScrolling(@NonNull Context context) {
- return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_NATURAL_SCROLLING, 0, UserHandle.USER_CURRENT) == 1;
- }
-
- /**
- * Sets the natural scroll behavior for the touchpad.
- *
- * If natural scrolling is enabled, moving two fingers upwards on the
- * touchpad will scroll down.
- *
- * @param context The application context.
- * @param enabled Will enable natural scroll if true, disable it if false
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public void setTouchpadNaturalScrolling(@NonNull Context context, boolean enabled) {
- Settings.System.putIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_NATURAL_SCROLLING, enabled ? 1 : 0,
- UserHandle.USER_CURRENT);
- }
-
- /**
- * Returns true if the touchpad should use tap to click.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return Whether the touchpad should use tap to click.
- *
- * @hide
- */
- public boolean useTouchpadTapToClick(@NonNull Context context) {
- return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_TAP_TO_CLICK, 0, UserHandle.USER_CURRENT) == 1;
- }
-
- /**
- * Sets the tap to click behavior for the touchpad.
- *
- * The new behavior is only applied to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @param enabled Will enable tap to click if true, disable it if false
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public void setTouchpadTapToClick(@NonNull Context context, boolean enabled) {
- Settings.System.putIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_TAP_TO_CLICK, enabled ? 1 : 0,
- UserHandle.USER_CURRENT);
- }
-
- /**
- * Returns true if the touchpad should use tap dragging.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return Whether the touchpad should use tap dragging.
- *
- * @hide
- */
- public boolean useTouchpadTapDragging(@NonNull Context context) {
- // TODO: obtain the actual behavior from the settings
- return true;
- }
-
- /**
- * Sets the tap dragging behavior for the touchpad.
- *
- * The new behavior is only applied to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @param enabled Will enable tap dragging if true, disable it if false
- *
- * @hide
- */
- public void setTouchpadTapDragging(@NonNull Context context, boolean enabled) {
- // TODO: set the right setting
- }
-
- /**
- * Returns true if the touchpad should use the right click zone.
- *
- * The returned value only applies to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @return Whether the touchpad should use the right click zone.
- *
- * @hide
- */
- public boolean useTouchpadRightClickZone(@NonNull Context context) {
- return Settings.System.getIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, 0, UserHandle.USER_CURRENT) == 1;
- }
-
- /**
- * Sets the right click zone behavior for the touchpad.
- *
- * The new behavior is only applied to gesture-compatible touchpads.
- *
- * @param context The application context.
- * @param enabled Will enable the right click zone if true, disable it if false
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
- public void setTouchpadRightClickZone(@NonNull Context context, boolean enabled) {
- Settings.System.putIntForUser(context.getContentResolver(),
- Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0,
- UserHandle.USER_CURRENT);
- }
-
- /**
* Registers a Keyboard backlight change listener to be notified about {@link
* KeyboardBacklightState} changes for connected keyboard devices.
*
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
new file mode 100644
index 0000000..cdf9ea5
--- /dev/null
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -0,0 +1,319 @@
+/*
+ * 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.hardware.input;
+
+import android.Manifest;
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * InputSettings encapsulates reading and writing settings related to input
+ *
+ * @hide
+ */
+@TestApi
+public class InputSettings {
+ /**
+ * Pointer Speed: The minimum (slowest) pointer speed (-7).
+ * @hide
+ */
+ public static final int MIN_POINTER_SPEED = -7;
+
+ /**
+ * Pointer Speed: The maximum (fastest) pointer speed (7).
+ * @hide
+ */
+ public static final int MAX_POINTER_SPEED = 7;
+
+ /**
+ * Pointer Speed: The default pointer speed (0).
+ * @hide
+ */
+ public static final int DEFAULT_POINTER_SPEED = 0;
+
+ /**
+ * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1).
+ * @hide
+ */
+ public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f;
+
+
+ private InputSettings() {
+ }
+
+ /**
+ * Gets the mouse pointer speed.
+ * <p>
+ * Only returns the permanent mouse pointer speed. Ignores any temporary pointer
+ * speed set by {@link InputManager#tryPointerSpeed}.
+ * </p>
+ *
+ * @param context The application context.
+ * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ @SuppressLint("NonUserGetterCalled")
+ public static int getPointerSpeed(Context context) {
+ return Settings.System.getInt(context.getContentResolver(),
+ Settings.System.POINTER_SPEED, DEFAULT_POINTER_SPEED);
+ }
+
+ /**
+ * Sets the mouse pointer speed.
+ * <p>
+ * Requires {@link android.Manifest.permission#WRITE_SETTINGS}.
+ * </p>
+ *
+ * @param context The application context.
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setPointerSpeed(Context context, int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ Settings.System.putInt(context.getContentResolver(),
+ Settings.System.POINTER_SPEED, speed);
+ }
+
+ /**
+ * Returns the maximum allowed obscuring opacity per UID to propagate touches.
+ *
+ * <p>For certain window types (e.g. {@link LayoutParams#TYPE_APPLICATION_OVERLAY}),
+ * the decision of honoring {@link LayoutParams#FLAG_NOT_TOUCHABLE} or not depends on
+ * the combined obscuring opacity of the windows above the touch-consuming window, per
+ * UID. Check documentation of {@link LayoutParams#FLAG_NOT_TOUCHABLE} for more details.
+ *
+ * <p>The value returned is between 0 (inclusive) and 1 (inclusive).
+ *
+ * @see LayoutParams#FLAG_NOT_TOUCHABLE
+ *
+ * @hide
+ */
+ @FloatRange(from = 0, to = 1)
+ public static float getMaximumObscuringOpacityForTouch(Context context) {
+ return Settings.Global.getFloat(context.getContentResolver(),
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+ DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
+ }
+
+ /**
+ * Sets the maximum allowed obscuring opacity by UID to propagate touches.
+ *
+ * <p>For certain window types (e.g. SAWs), the decision of honoring {@link LayoutParams
+ * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows
+ * above the touch-consuming window.
+ *
+ * <p>For a certain UID:
+ * <ul>
+ * <li>If it's the same as the UID of the touch-consuming window, allow it to propagate
+ * the touch.
+ * <li>Otherwise take all its windows of eligible window types above the touch-consuming
+ * window, compute their combined obscuring opacity considering that {@code
+ * opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is
+ * less than or equal to this setting and there are no other windows preventing the
+ * touch, allow the UID to propagate the touch.
+ * </ul>
+ *
+ * <p>This value should be between 0 (inclusive) and 1 (inclusive).
+ *
+ * @see #getMaximumObscuringOpacityForTouch(Context)
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public static void setMaximumObscuringOpacityForTouch(
+ @NonNull Context context,
+ @FloatRange(from = 0, to = 1) float opacity) {
+ if (opacity < 0 || opacity > 1) {
+ throw new IllegalArgumentException(
+ "Maximum obscuring opacity for touch should be >= 0 and <= 1");
+ }
+ Settings.Global.putFloat(context.getContentResolver(),
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity);
+ }
+
+ /**
+ * Whether stylus has ever been used on device (false by default).
+ * @hide
+ */
+ public static boolean isStylusEverUsed(@NonNull Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.STYLUS_EVER_USED, 0) == 1;
+ }
+
+ /**
+ * Set whether stylus has ever been used on device.
+ * Should only ever be set to true once after stylus first usage.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public static void setStylusEverUsed(@NonNull Context context, boolean stylusEverUsed) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.STYLUS_EVER_USED, stylusEverUsed ? 1 : 0);
+ }
+
+
+ /**
+ * Gets the touchpad pointer speed.
+ *
+ * The returned value only applies to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public static int getTouchpadPointerSpeed(@NonNull Context context) {
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_POINTER_SPEED, DEFAULT_POINTER_SPEED,
+ UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Sets the touchpad pointer speed, and saves it in the settings.
+ *
+ * The new speed will only apply to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setTouchpadPointerSpeed(@NonNull Context context, int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_POINTER_SPEED, speed, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Returns true if moving two fingers upwards on the touchpad should
+ * scroll down, which is known as natural scrolling.
+ *
+ * The returned value only applies to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @return Whether the touchpad should use natural scrolling.
+ *
+ * @hide
+ */
+ public static boolean useTouchpadNaturalScrolling(@NonNull Context context) {
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_NATURAL_SCROLLING, 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * Sets the natural scroll behavior for the touchpad.
+ *
+ * If natural scrolling is enabled, moving two fingers upwards on the
+ * touchpad will scroll down.
+ *
+ * @param context The application context.
+ * @param enabled Will enable natural scroll if true, disable it if false
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setTouchpadNaturalScrolling(@NonNull Context context, boolean enabled) {
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_NATURAL_SCROLLING, enabled ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Returns true if the touchpad should use tap to click.
+ *
+ * The returned value only applies to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @return Whether the touchpad should use tap to click.
+ *
+ * @hide
+ */
+ public static boolean useTouchpadTapToClick(@NonNull Context context) {
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_TAP_TO_CLICK, 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * Sets the tap to click behavior for the touchpad.
+ *
+ * The new behavior is only applied to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @param enabled Will enable tap to click if true, disable it if false
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setTouchpadTapToClick(@NonNull Context context, boolean enabled) {
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_TAP_TO_CLICK, enabled ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Returns true if the touchpad should use the right click zone.
+ *
+ * The returned value only applies to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @return Whether the touchpad should use the right click zone.
+ *
+ * @hide
+ */
+ public static boolean useTouchpadRightClickZone(@NonNull Context context) {
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, 0, UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
+ * Sets the right click zone behavior for the touchpad.
+ *
+ * The new behavior is only applied to gesture-compatible touchpads.
+ *
+ * @param context The application context.
+ * @param enabled Will enable the right click zone if true, disable it if false
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setTouchpadRightClickZone(@NonNull Context context, boolean enabled) {
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13d54ef..03c32d70 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";
@@ -2984,6 +2982,12 @@
/**
* Signals that wake-on-lan/wake-on-wlan is allowed in Low Power Standby.
*
+ * <p>If Low Power Standby is enabled ({@link #isLowPowerStandbyEnabled()}),
+ * wake-on-lan/wake-on-wlan may not be available while in standby.
+ * Use {@link #isAllowedInLowPowerStandby(String)} to determine whether the device allows this
+ * feature to be used during Low Power Standby with the currently active Low Power Standby
+ * policy.
+ *
* @see #isAllowedInLowPowerStandby(String)
*/
public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN =
diff --git a/core/java/android/service/search/ISearchUiService.aidl b/core/java/android/service/search/ISearchUiService.aidl
index bc6d421..f59347f 100644
--- a/core/java/android/service/search/ISearchUiService.aidl
+++ b/core/java/android/service/search/ISearchUiService.aidl
@@ -39,8 +39,6 @@
void onRegisterEmptyQueryResultUpdateCallback (in SearchSessionId sessionId, in ISearchCallback callback);
- void onRequestEmptyQueryResultUpdate(in SearchSessionId sessionId);
-
void onUnregisterEmptyQueryResultUpdateCallback(in SearchSessionId sessionId, in ISearchCallback callback);
void onDestroy(in SearchSessionId sessionId);
diff --git a/core/java/android/service/search/SearchUiService.java b/core/java/android/service/search/SearchUiService.java
index 55a96fa..8d05b80 100644
--- a/core/java/android/service/search/SearchUiService.java
+++ b/core/java/android/service/search/SearchUiService.java
@@ -112,12 +112,6 @@
}
@Override
- public void onRequestEmptyQueryResultUpdate(SearchSessionId sessionId) {
- mHandler.sendMessage(obtainMessage(SearchUiService::doRequestEmptyQueryResultUpdate,
- SearchUiService.this, sessionId));
- }
-
- @Override
public void onUnregisterEmptyQueryResultUpdateCallback(SearchSessionId sessionId,
ISearchCallback callback) {
mHandler.sendMessage(
@@ -220,24 +214,6 @@
@MainThread
public void onStartUpdateEmptyQueryResult() {}
- private void doRequestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {
- // Just an optimization, if there are no callbacks, then don't bother notifying the service
- final ArrayList<CallbackWrapper> callbacks = mSessionEmptyQueryResultCallbacks.get(
- sessionId);
- if (callbacks != null && !callbacks.isEmpty()) {
- onRequestEmptyQueryResultUpdate(sessionId);
- }
- }
-
- /**
- * Called by a client to request empty query search target result for zero state. This method
- * is only called if there are one or more empty query result update callbacks registered.
- *
- * @see #updateEmptyQueryResult(SearchSessionId, List)
- */
- @MainThread
- public void onRequestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {}
-
private void doUnregisterEmptyQueryResultUpdateCallback(@NonNull SearchSessionId sessionId,
@NonNull ISearchCallback callback) {
final ArrayList<CallbackWrapper> callbacks = mSessionEmptyQueryResultCallbacks.get(
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/Choreographer.java b/core/java/android/view/Choreographer.java
index d0acedb..4a83bbe 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -1173,7 +1173,8 @@
*
* @param data The payload which includes frame information. Divide nanosecond values by
* {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
- * time base.
+ * time base. {@code data} is not valid outside of {@code onVsync} and should
+ * not be accessed outside the callback.
* @see FrameCallback#doFrame
**/
void onVsync(@NonNull FrameData data);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 6b1499f..1563fc0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -56,6 +56,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Provides information about the size and density of a logical display.
@@ -111,6 +113,8 @@
private int mCachedAppWidthCompat;
private int mCachedAppHeightCompat;
+ private ArrayList<HdrSdrRatioListenerWrapper> mHdrSdrRatioListeners = new ArrayList<>();
+
/**
* The default Display id, which is the id of the primary display assuming there is one.
*/
@@ -1292,6 +1296,102 @@
}
/**
+ * @return Whether the display supports reporting an hdr/sdr ratio. If this is false,
+ * {@link #getHdrSdrRatio()} will always be 1.0f
+ * @hide
+ * TODO: make public
+ */
+ public boolean isHdrSdrRatioAvailable() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ return !Float.isNaN(mDisplayInfo.hdrSdrRatio);
+ }
+ }
+
+ /**
+ * @return The current hdr/sdr ratio expressed as the ratio of targetHdrPeakBrightnessInNits /
+ * targetSdrWhitePointInNits. If {@link #isHdrSdrRatioAvailable()} is false, this
+ * always returns 1.0f.
+ *
+ * @hide
+ * TODO: make public
+ */
+ public float getHdrSdrRatio() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ return Float.isNaN(mDisplayInfo.hdrSdrRatio)
+ ? 1.0f : mDisplayInfo.hdrSdrRatio;
+ }
+ }
+
+ private int findHdrSdrRatioListenerLocked(Consumer<Display> listener) {
+ for (int i = 0; i < mHdrSdrRatioListeners.size(); i++) {
+ final HdrSdrRatioListenerWrapper wrapper = mHdrSdrRatioListeners.get(i);
+ if (wrapper.mListener == listener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Registers a listener that will be invoked whenever the display's hdr/sdr ratio has changed.
+ * After receiving the callback on the specified Executor, call {@link #getHdrSdrRatio()} to
+ * get the updated value.
+ * If {@link #isHdrSdrRatioAvailable()} is false, then an IllegalStateException will be thrown
+ *
+ * @see #unregisterHdrSdrRatioChangedListener(Consumer)
+ * @param executor The executor to invoke the listener on
+ * @param listener The listener to invoke when the HDR/SDR ratio changes
+ * @throws IllegalStateException if {@link #isHdrSdrRatioAvailable()} is false
+ * @hide
+ * TODO: Make public
+ */
+ public void registerHdrSdrRatioChangedListener(@NonNull Executor executor,
+ @NonNull Consumer<Display> listener) {
+ if (!isHdrSdrRatioAvailable()) {
+ throw new IllegalStateException("HDR/SDR ratio changed not available");
+ }
+ HdrSdrRatioListenerWrapper toRegister = null;
+ synchronized (mLock) {
+ if (findHdrSdrRatioListenerLocked(listener) == -1) {
+ toRegister = new HdrSdrRatioListenerWrapper(listener);
+ mHdrSdrRatioListeners.add(toRegister);
+ } // else already listening, don't do anything
+ }
+ if (toRegister != null) {
+ // Although we only care about the HDR/SDR ratio changing, that can also come in the
+ // form of the larger DISPLAY_CHANGED event
+ mGlobal.registerDisplayListener(toRegister, executor,
+ DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED
+ | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ }
+
+ }
+
+ /**
+ * @param listener The previously
+ * {@link #registerHdrSdrRatioChangedListener(Executor, Consumer) registered}
+ * hdr/sdr ratio listener to remove.
+ *
+ * @see #registerHdrSdrRatioChangedListener(Executor, Consumer)
+ * @hide
+ * TODO: Make public
+ */
+ public void unregisterHdrSdrRatioChangedListener(Consumer<Display> listener) {
+ HdrSdrRatioListenerWrapper toRemove = null;
+ synchronized (mLock) {
+ int index = findHdrSdrRatioListenerLocked(listener);
+ if (index != -1) {
+ toRemove = mHdrSdrRatioListeners.remove(index);
+ }
+ }
+ if (toRemove != null) {
+ mGlobal.unregisterDisplayListener(toRemove);
+ }
+ }
+
+ /**
* Sets the default {@link Display.Mode} to use for the display. The display mode includes
* preference for resolution and refresh rate.
* If the mode specified is not supported by the display, then no mode change occurs.
@@ -2528,4 +2628,33 @@
}
}
}
+
+ private class HdrSdrRatioListenerWrapper implements DisplayManager.DisplayListener {
+ Consumer<Display> mListener;
+ float mLastReportedRatio = 1.f;
+
+ private HdrSdrRatioListenerWrapper(Consumer<Display> listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // don't care
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ // don't care
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == getDisplayId()) {
+ float newRatio = getHdrSdrRatio();
+ if (newRatio != mLastReportedRatio) {
+ mListener.accept(Display.this);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 3a02c48..0368918 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -39,6 +39,8 @@
import android.util.DisplayMetrics;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.display.BrightnessSynchronizer;
+
import java.util.Arrays;
import java.util.Objects;
@@ -340,6 +342,13 @@
@Nullable
public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
+ /**
+ * The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio
+ * queries then this is NaN
+ */
+ public float hdrSdrRatio = Float.NaN;
+
+
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
@@ -415,7 +424,8 @@
&& Objects.equals(roundedCorners, other.roundedCorners)
&& installOrientation == other.installOrientation
&& Objects.equals(displayShape, other.displayShape)
- && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate);
+ && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
+ && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio);
}
@Override
@@ -471,6 +481,7 @@
installOrientation = other.installOrientation;
displayShape = other.displayShape;
layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
+ hdrSdrRatio = other.hdrSdrRatio;
}
public void readFromParcel(Parcel source) {
@@ -532,6 +543,7 @@
installOrientation = source.readInt();
displayShape = source.readTypedObject(DisplayShape.CREATOR);
layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
+ hdrSdrRatio = source.readFloat();
}
@Override
@@ -591,6 +603,7 @@
dest.writeInt(installOrientation);
dest.writeTypedObject(displayShape, flags);
dest.writeTypedObject(layoutLimitedRefreshRate, flags);
+ dest.writeFloat(hdrSdrRatio);
}
@Override
@@ -852,6 +865,12 @@
sb.append(Surface.rotationToString(installOrientation));
sb.append(", layoutLimitedRefreshRate ");
sb.append(layoutLimitedRefreshRate);
+ sb.append(", hdrSdrRatio ");
+ if (Float.isNaN(hdrSdrRatio)) {
+ sb.append("not_available");
+ } else {
+ sb.append(hdrSdrRatio);
+ }
sb.append("}");
return sb.toString();
}
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/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 159775c..d1c4201 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -169,7 +169,7 @@
private static final boolean DEBUG_UNDO = false;
// TODO(nona): Make this configurable.
- private static final boolean FLAG_USE_NEW_CONTEXT_MENU = true;
+ 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;
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.bp b/core/jni/Android.bp
index b4599c8..fc26766 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -334,8 +334,6 @@
"libtimeinstate",
"server_configurable_flags",
"libimage_io",
- "libjpegdecoder",
- "libjpegencoder",
"libjpegrecoverymap",
],
export_shared_lib_headers: [
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 688fec6..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 -->
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/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 111cfd8..f11836e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -650,7 +650,6 @@
}
mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
- mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
// If the displayId of the task is different than what PipBoundsHandler has, then update
// it. This is possible if we entered PiP on an external display.
@@ -659,6 +658,17 @@
mOnDisplayIdChangeCallback.accept(info.displayId);
}
+ // UiEvent logging.
+ final PipUiEventLogger.PipUiEventEnum uiEventEnum;
+ if (isLaunchIntoPipTask()) {
+ uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER_CONTENT_PIP;
+ } else if (mPipTransitionState.getInSwipePipToHomeTransition()) {
+ uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_AUTO_ENTER;
+ } else {
+ uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER;
+ }
+ mPipUiEventLoggerLogger.log(uiEventEnum);
+
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index 513ebba..3e5a19b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -78,6 +78,12 @@
@UiEvent(doc = "Activity enters picture-in-picture mode")
PICTURE_IN_PICTURE_ENTER(603),
+ @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
+ PICTURE_IN_PICTURE_AUTO_ENTER(1313),
+
+ @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
+ PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
+
@UiEvent(doc = "Expands from picture-in-picture to fullscreen")
PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
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/Android.bp b/libs/hwui/Android.bp
index 9e3f115..03d89cc 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -396,8 +396,6 @@
"libharfbuzz_ng",
"libimage_io",
"libjpeg",
- "libjpegdecoder",
- "libjpegencoder",
"libjpegrecoverymap",
"liblog",
"libminikin",
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 6d7c727..8266beb 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -17,13 +17,25 @@
#include "ImageDecoder.h"
#include <Gainmap.h>
+#include <SkAlphaType.h>
#include <SkAndroidCodec.h>
#include <SkBitmap.h>
#include <SkBlendMode.h>
#include <SkCanvas.h>
+#include <SkCodec.h>
+#include <SkCodecAnimation.h>
+#include <SkColorSpace.h>
+#include <SkColorType.h>
#include <SkEncodedOrigin.h>
+#include <SkImageInfo.h>
#include <SkGainmapInfo.h>
+#include <SkMatrix.h>
#include <SkPaint.h>
+#include <SkPngChunkReader.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkSamplingOptions.h>
+#include <SkSize.h>
#include <SkStream.h>
#include <hwui/Bitmap.h>
#include <log/log.h>
@@ -506,6 +518,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 +543,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/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index add62b1..fda7080 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -18,11 +18,16 @@
#include <FrontBufferedStream.h>
#include <HardwareBitmapUploader.h>
+#include <SkAlphaType.h>
#include <SkAndroidCodec.h>
#include <SkBitmap.h>
+#include <SkCodec.h>
+#include <SkCodecAnimation.h>
#include <SkColorSpace.h>
+#include <SkColorType.h>
#include <SkImageInfo.h>
#include <SkRect.h>
+#include <SkSize.h>
#include <SkStream.h>
#include <SkString.h>
#include <androidfw/Asset.h>
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/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/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index cd6ed23..e18b4a9 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -25,10 +25,14 @@
#include <hwui/ImageDecoder.h>
#include <log/log.h>
#include <SkAndroidCodec.h>
+#include <SkAlphaType.h>
#include <SkCodec.h>
+#include <SkCodecAnimation.h>
#include <SkColorSpace.h>
+#include <SkColorType.h>
#include <SkImageInfo.h>
#include <SkRect.h>
+#include <SkRefCnt.h>
#include <SkSize.h>
#include <SkStream.h>
#include <utils/Color.h>
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/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/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/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/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/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/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/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/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 c45af6d..754433b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2304,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>
@@ -3021,4 +3029,22 @@
[CHAR LIMIT=32]
-->
<string name="lock_screen_settings">Lock screen settings</string>
+
+ <!-- Content description for Wi-Fi not available icon on dream [CHAR LIMIT=NONE]-->
+ <string name="wifi_unavailable_dream_overlay_content_description">Wi-Fi not available</string>
+
+ <!-- Content description for camera blocked icon on dream [CHAR LIMIT=NONE] -->
+ <string name="camera_blocked_dream_overlay_content_description">Camera blocked</string>
+
+ <!-- Content description for camera and microphone blocked icon on dream [CHAR LIMIT=NONE] -->
+ <string name="camera_and_microphone_blocked_dream_overlay_content_description">Camera and microphone blocked</string>
+
+ <!-- Content description for camera and microphone disabled icon on dream [CHAR LIMIT=NONE] -->
+ <string name="microphone_blocked_dream_overlay_content_description">Microphone blocked</string>
+
+ <!-- Content description for priority mode icon on dream [CHAR LIMIT=NONE] -->
+ <string name="priority_mode_dream_overlay_content_description">Priority mode on</string>
+
+ <!-- Content description for when assistant attention is active [CHAR LIMIT=NONE] -->
+ <string name="assistant_attention_content_description">Assistant attention on</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index 54ae84f9..ead1a10 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -303,9 +303,18 @@
pw.println(" requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup")
pw.println(" requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent")
pw.println(" requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail")
- pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=${
- onUnlockIntentWhenBiometricEnrolled.map { BiometricType.values()[it] }
- }")
+
+ val onUnlockIntentWhenBiometricEnrolledString =
+ onUnlockIntentWhenBiometricEnrolled.map {
+ for (biometricType in BiometricType.values()) {
+ if (biometricType.intValue == it) {
+ return@map biometricType.name
+ }
+ }
+ return@map "UNKNOWN"
+ }
+ pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" +
+ "$onUnlockIntentWhenBiometricEnrolledString")
pw.println(" requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn")
pw.println(" requestActiveUnlockOnFaceAcquireInfo=" +
"$faceAcquireInfoToTriggerBiometricFailOn")
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/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 27641fe..a14aa52 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -269,6 +269,8 @@
*/
private void addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
mWindow = new PhoneWindow(mContext);
+ // Default to SystemUI name for TalkBack.
+ mWindow.setTitle("");
mWindow.setAttributes(layoutParams);
mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 2221a04..74a49a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -259,7 +259,8 @@
mConnectivityManager.getActiveNetwork());
final boolean available = capabilities != null
&& capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+ showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available,
+ R.string.wifi_unavailable_dream_overlay_content_description);
}
private void updateAlarmStatusIcon() {
@@ -274,7 +275,8 @@
private void updateAssistantAttentionIcon() {
showIcon(DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
- mDreamOverlayStateController.hasAssistantAttention());
+ mDreamOverlayStateController.hasAssistantAttention(),
+ R.string.assistant_attention_content_description);
}
private void updateVisibility() {
@@ -304,13 +306,16 @@
@DreamOverlayStatusBarView.StatusIconType int iconType = Resources.ID_NULL;
showIcon(
DreamOverlayStatusBarView.STATUS_ICON_CAMERA_DISABLED,
- !micBlocked && cameraBlocked);
+ !micBlocked && cameraBlocked,
+ R.string.camera_blocked_dream_overlay_content_description);
showIcon(
DreamOverlayStatusBarView.STATUS_ICON_MIC_DISABLED,
- micBlocked && !cameraBlocked);
+ micBlocked && !cameraBlocked,
+ R.string.microphone_blocked_dream_overlay_content_description);
showIcon(
DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
- micBlocked && cameraBlocked);
+ micBlocked && cameraBlocked,
+ R.string.camera_and_microphone_blocked_dream_overlay_content_description);
}
private String buildNotificationsContentDescription(int notificationCount) {
@@ -323,11 +328,13 @@
private void updatePriorityModeStatusIcon() {
showIcon(
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
- mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
+ mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF,
+ R.string.priority_mode_dream_overlay_content_description);
}
- private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
- showIcon(iconType, show, null);
+ private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show,
+ int contentDescriptionResId) {
+ showIcon(iconType, show, mResources.getString(contentDescriptionResId));
}
private void showIcon(
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b75b6d8..85e050c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -566,6 +566,12 @@
val CONTROLS_MANAGEMENT_NEW_FLOWS =
releasedFlag(2002, "controls_management_new_flows", teamfood = true)
+ // Enables removing app from Home control panel as a part of a new flow
+ // TODO(b/269132640): Tracking Bug
+ @JvmField
+ val APP_PANELS_REMOVE_APPS_ALLOWED =
+ unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = false)
+
// 2100 - Falsing Manager
@JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index 5a9f775..c9f645d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.pm.PackageManager
import com.android.systemui.R
@@ -27,10 +28,14 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.withContext
@SysUISingleton
class CameraQuickAffordanceConfig
@@ -39,6 +44,9 @@
@Application private val context: Context,
private val packageManager: PackageManager,
private val cameraGestureHelper: Lazy<CameraGestureHelper>,
+ private val userTracker: UserTracker,
+ private val devicePolicyManager: DevicePolicyManager,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig {
override val key: String
@@ -79,7 +87,12 @@
return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
- private fun isLaunchable(): Boolean {
- return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
+ private suspend fun isLaunchable(): Boolean {
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) &&
+ withContext(backgroundDispatcher) {
+ !devicePolicyManager.getCameraDisabled(null, userTracker.userId) &&
+ devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId) and
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA == 0
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
index d9ec3b1..6f821a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.Intent
import com.android.systemui.ActivityIntentHelper
@@ -29,10 +30,13 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.withContext
@SysUISingleton
class VideoCameraQuickAffordanceConfig
@@ -42,6 +46,8 @@
private val cameraIntents: CameraIntentsWrapper,
private val activityIntentHelper: ActivityIntentHelper,
private val userTracker: UserTracker,
+ private val devicePolicyManager: DevicePolicyManager,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) : KeyguardQuickAffordanceConfig {
private val intent: Intent by lazy {
@@ -63,8 +69,8 @@
get() = R.drawable.ic_videocam
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
- get() =
- flowOf(
+ get() = flow {
+ emit(
if (isLaunchable()) {
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon =
@@ -77,6 +83,7 @@
KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
)
+ }
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return if (isLaunchable()) {
@@ -95,11 +102,14 @@
)
}
- private fun isLaunchable(): Boolean {
+ private suspend fun isLaunchable(): Boolean {
return activityIntentHelper.getTargetActivityInfo(
intent,
userTracker.userId,
true,
- ) != null
+ ) != null &&
+ withContext(backgroundDispatcher) {
+ !devicePolicyManager.getCameraDisabled(null, userTracker.userId)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index b72923a..68d2c5c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -164,13 +164,13 @@
mediaCarouselScrollHandler.scrollToStart()
}
}
- private var currentlyExpanded = true
+
+ @VisibleForTesting
+ var currentlyExpanded = true
set(value) {
if (field != value) {
field = value
- for (player in MediaPlayerData.players()) {
- player.setListening(field)
- }
+ updateSeekbarListening(mediaCarouselScrollHandler.visibleToUser)
}
}
@@ -259,6 +259,7 @@
executor,
this::onSwipeToDismiss,
this::updatePageIndicatorLocation,
+ this::updateSeekbarListening,
this::closeGuts,
falsingCollector,
falsingManager,
@@ -590,6 +591,17 @@
?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex)
}
}
+ // Check postcondition: mediaContent should have the same number of children as there
+ // are
+ // elements in mediaPlayers.
+ if (MediaPlayerData.players().size != mediaContent.childCount) {
+ Log.e(
+ TAG,
+ "Size of players list and number of views in carousel are out of sync. " +
+ "Players size is ${MediaPlayerData.players().size}. " +
+ "View count is ${mediaContent.childCount}."
+ )
+ }
}
// Returns true if new player is added
@@ -618,7 +630,9 @@
)
newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
newPlayer.bindPlayer(data, key)
- newPlayer.setListening(currentlyExpanded)
+ newPlayer.setListening(
+ mediaCarouselScrollHandler.visibleToUser && currentlyExpanded
+ )
MediaPlayerData.addMediaPlayer(
key,
data,
@@ -665,17 +679,6 @@
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
mediaFrame.requiresRemeasuring = true
- // Check postcondition: mediaContent should have the same number of children as there
- // are
- // elements in mediaPlayers.
- if (MediaPlayerData.players().size != mediaContent.childCount) {
- Log.e(
- TAG,
- "Size of players list and number of views in carousel are out of sync. " +
- "Players size is ${MediaPlayerData.players().size}. " +
- "View count is ${mediaContent.childCount}."
- )
- }
return existingPlayer == null
}
@@ -914,6 +917,13 @@
.toFloat()
}
+ /** Update listening to seekbar. */
+ private fun updateSeekbarListening(visibleToUser: Boolean) {
+ for (player in MediaPlayerData.players()) {
+ player.setListening(visibleToUser && currentlyExpanded)
+ }
+ }
+
/** Update the dimension of this carousel. */
private fun updateCarouselDimensions() {
var width = 0
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index 36b2eda..1ace316 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -57,6 +57,7 @@
private val mainExecutor: DelayableExecutor,
val dismissCallback: () -> Unit,
private var translationChangedListener: () -> Unit,
+ private var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit,
private val closeGuts: (immediate: Boolean) -> Unit,
private val falsingCollector: FalsingCollector,
private val falsingManager: FalsingManager,
@@ -177,6 +178,12 @@
/** Whether the media card is visible to user if any */
var visibleToUser: Boolean = false
+ set(value) {
+ if (field != value) {
+ field = value
+ seekBarUpdateListener.invoke(field)
+ }
+ }
/** Whether the quick setting is expanded or not */
var qsExpanded: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 6076e58..288266a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -347,6 +347,11 @@
mSeekBarViewModel.setListening(listening);
}
+ @VisibleForTesting
+ public boolean getListening() {
+ return mSeekBarViewModel.getListening();
+ }
+
/** Sets whether the user is touching the seek bar to change the track position. */
private void setIsScrubbing(boolean isScrubbing) {
if (mMediaData == null || mMediaData.getSemanticActions() == null) {
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/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 7a62bae..fc94aed 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -93,7 +93,13 @@
@UiEvent(doc = "User has discarded the result of a long screenshot")
SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
@UiEvent(doc = "A screenshot has been taken and saved to work profile")
- SCREENSHOT_SAVED_TO_WORK_PROFILE(1240);
+ SCREENSHOT_SAVED_TO_WORK_PROFILE(1240),
+ @UiEvent(doc = "Notes application triggered the screenshot for notes")
+ SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
+ @UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
+ SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
+ @UiEvent(doc = "User cancelled the screenshot for notes app flow")
+ SCREENSHOT_FOR_NOTE_CANCELLED(1310);
private final int mId;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index f8d86a0..3133924 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -17,15 +17,21 @@
package com.android.systemui.screenshot;
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
+import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME;
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER;
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
@@ -33,15 +39,20 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import androidx.activity.ComponentActivity;
+import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLogger.UiEventEnum;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.settings.UserTracker;
import javax.inject.Inject;
@@ -64,9 +75,15 @@
*
* TODO(b/267309532): Polish UI and animations.
*/
-public final class AppClipsActivity extends ComponentActivity {
+public class AppClipsActivity extends ComponentActivity {
+
+ private static final String TAG = AppClipsActivity.class.getSimpleName();
+ private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
private final AppClipsViewModel.Factory mViewModelFactory;
+ private final PackageManager mPackageManager;
+ private final UserTracker mUserTracker;
+ private final UiEventLogger mUiEventLogger;
private final BroadcastReceiver mBroadcastReceiver;
private final IntentFilter mIntentFilter;
@@ -80,10 +97,17 @@
private AppClipsViewModel mViewModel;
private ResultReceiver mResultReceiver;
+ @Nullable
+ private String mCallingPackageName;
+ private int mCallingPackageUid;
@Inject
- public AppClipsActivity(AppClipsViewModel.Factory viewModelFactory) {
+ public AppClipsActivity(AppClipsViewModel.Factory viewModelFactory,
+ PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger) {
mViewModelFactory = viewModelFactory;
+ mPackageManager = packageManager;
+ mUserTracker = userTracker;
+ mUiEventLogger = uiEventLogger;
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -113,6 +137,7 @@
RECEIVER_NOT_EXPORTED);
Intent intent = getIntent();
+ setUpUiLogging(intent);
mResultReceiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER, ResultReceiver.class);
if (mResultReceiver == null) {
setErrorThenFinish(Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED);
@@ -169,6 +194,17 @@
}
}
+ private void setUpUiLogging(Intent intent) {
+ mCallingPackageName = intent.getStringExtra(EXTRA_CALLING_PACKAGE_NAME);
+ mCallingPackageUid = 0;
+ try {
+ mCallingPackageUid = mPackageManager.getApplicationInfoAsUser(mCallingPackageName,
+ APPLICATION_INFO_FLAGS, mUserTracker.getUserId()).uid;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Couldn't find notes app UID " + e);
+ }
+ }
+
private void setScreenshot(Bitmap screenshot) {
// Set background, status and navigation bar colors as the activity is no longer
// translucent.
@@ -228,6 +264,7 @@
data.putParcelable(EXTRA_SCREENSHOT_URI, uri);
try {
mResultReceiver.send(Activity.RESULT_OK, data);
+ logUiEvent(SCREENSHOT_FOR_NOTE_ACCEPTED);
} catch (Exception e) {
// Do nothing.
}
@@ -251,6 +288,9 @@
data.putInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE, errorCode);
try {
mResultReceiver.send(RESULT_OK, data);
+ if (errorCode == Intent.CAPTURE_CONTENT_FOR_NOTE_USER_CANCELED) {
+ logUiEvent(SCREENSHOT_FOR_NOTE_CANCELLED);
+ }
} catch (Exception e) {
// Do nothing.
}
@@ -259,6 +299,10 @@
mResultReceiver = null;
}
+ private void logUiEvent(UiEventEnum uiEvent) {
+ mUiEventLogger.log(uiEvent, mCallingPackageUid, mCallingPackageName);
+ }
+
private void updateImageDimensions() {
Drawable drawable = mPreview.getDrawable();
if (drawable == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
index 4759cc6..1946b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
@@ -24,26 +24,33 @@
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.ResultReceiver;
+import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.notetask.NoteTaskController;
+import com.android.systemui.settings.UserTracker;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
@@ -70,15 +77,23 @@
public class AppClipsTrampolineActivity extends Activity {
private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName();
- public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+ static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI";
- public static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
- static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
+ static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
+ private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
private final DevicePolicyManager mDevicePolicyManager;
private final FeatureFlags mFeatureFlags;
private final Optional<Bubbles> mOptionalBubbles;
private final NoteTaskController mNoteTaskController;
+ private final PackageManager mPackageManager;
+ private final UserTracker mUserTracker;
+ private final UiEventLogger mUiEventLogger;
private final ResultReceiver mResultReceiver;
private Intent mKillAppClipsBroadcastIntent;
@@ -86,11 +101,15 @@
@Inject
public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags,
Optional<Bubbles> optionalBubbles, NoteTaskController noteTaskController,
+ PackageManager packageManager, UserTracker userTracker, UiEventLogger uiEventLogger,
@Main Handler mainHandler) {
mDevicePolicyManager = devicePolicyManager;
mFeatureFlags = flags;
mOptionalBubbles = optionalBubbles;
mNoteTaskController = noteTaskController;
+ mPackageManager = packageManager;
+ mUserTracker = userTracker;
+ mUiEventLogger = uiEventLogger;
mResultReceiver = createResultReceiver(mainHandler);
}
@@ -138,8 +157,12 @@
return;
}
- Intent intent = new Intent().setComponent(componentName).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK).putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver);
+ String callingPackageName = getCallingPackage();
+ Intent intent = new Intent().setComponent(componentName)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
+ .putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
+
try {
// Start the App Clips activity.
startActivity(intent);
@@ -150,6 +173,9 @@
new Intent(ACTION_FINISH_FROM_TRAMPOLINE)
.setComponent(componentName)
.setPackage(componentName.getPackageName());
+
+ // Log successful triggering of screenshot for notes.
+ logScreenshotTriggeredUiEvent(callingPackageName);
} catch (ActivityNotFoundException e) {
setErrorResultAndFinish(CAPTURE_CONTENT_FOR_NOTE_FAILED);
}
@@ -170,6 +196,18 @@
finish();
}
+ private void logScreenshotTriggeredUiEvent(@Nullable String callingPackageName) {
+ int callingPackageUid = 0;
+ try {
+ callingPackageUid = mPackageManager.getApplicationInfoAsUser(callingPackageName,
+ APPLICATION_INFO_FLAGS, mUserTracker.getUserId()).uid;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Couldn't find notes app UID " + e);
+ }
+
+ mUiEventLogger.log(SCREENSHOT_FOR_NOTE_TRIGGERED, callingPackageUid, callingPackageName);
+ }
+
private class AppClipsResultReceiver extends ResultReceiver {
AppClipsResultReceiver(Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
index 5a7b5f9..b2910fd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
@@ -18,6 +18,8 @@
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
+import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
+
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
@@ -29,6 +31,7 @@
import android.os.Process;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
@@ -49,7 +52,8 @@
import javax.inject.Inject;
/** A {@link ViewModel} to help with the App Clips screenshot flow. */
-final class AppClipsViewModel extends ViewModel {
+@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+public final class AppClipsViewModel extends ViewModel {
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
private final ImageExporter mImageExporter;
@@ -76,7 +80,8 @@
}
/** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */
- void performScreenshot() {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public void performScreenshot() {
mBgExecutor.execute(() -> {
Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot();
mMainExecutor.execute(() -> {
@@ -90,12 +95,14 @@
}
/** Returns a {@link LiveData} that holds the captured screenshot. */
- LiveData<Bitmap> getScreenshot() {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public LiveData<Bitmap> getScreenshot() {
return mScreenshotLiveData;
}
/** Returns a {@link LiveData} that holds the {@link Uri} where screenshot is saved. */
- LiveData<Uri> getResultLiveData() {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public LiveData<Uri> getResultLiveData() {
return mResultLiveData;
}
@@ -103,7 +110,8 @@
* Returns a {@link LiveData} that holds the error codes for
* {@link Intent#EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE}.
*/
- LiveData<Integer> getErrorLiveData() {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public LiveData<Integer> getErrorLiveData() {
return mErrorLiveData;
}
@@ -111,7 +119,8 @@
* Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to
* {@link LiveData}.
*/
- void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
mBgExecutor.execute(() -> {
// Render the screenshot bitmap in background.
Bitmap screenshotBitmap = renderBitmap(screenshotDrawable, bounds);
@@ -151,7 +160,8 @@
}
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
- static final class Factory implements ViewModelProvider.Factory {
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
+ public static final class Factory implements ViewModelProvider.Factory {
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
private final ImageExporter mImageExporter;
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/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 2f34516..16c4027 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
+import android.os.ParcelUuid
+
/**
* SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the
* subscriptions themselves: subscriptionId and isOpportunistic. Any new fields that we need can be
@@ -29,4 +31,7 @@
* filtering in certain cases. See [MobileIconsInteractor] for the filtering logic
*/
val isOpportunistic: Boolean = false,
+
+ /** Subscriptions in the same group may be filtered or treated as a single subscription */
+ val groupUuid: ParcelUuid? = null,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index c9049d8..e77266f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -376,6 +376,7 @@
SubscriptionModel(
subscriptionId = subscriptionId,
isOpportunistic = isOpportunistic,
+ groupUuid = groupUuid,
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 72d5113..5a2e11e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -150,6 +150,12 @@
val info1 = unfilteredSubs[0]
val info2 = unfilteredSubs[1]
+
+ // Filtering only applies to subscriptions in the same group
+ if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
+ return@combine unfilteredSubs
+ }
+
// If both subscriptions are primary, show both
if (!info1.isOpportunistic && !info2.isOpportunistic) {
return@combine unfilteredSubs
@@ -186,7 +192,7 @@
* validated bit from the old active network (A) while data is changing to the new one (B).
*
* This condition only applies if
- * 1. A and B are in the same subscription group (e.c. for CBRS data switching) and
+ * 1. A and B are in the same subscription group (e.g. for CBRS data switching) and
* 2. A was validated before the switch
*
* The goal of this is to minimize the flickering in the UI of the cellular indicator
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 3f54aebf..c0cbd62 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -21,6 +21,7 @@
import android.content.Context
import android.hardware.BatteryState
import android.hardware.input.InputManager
+import android.hardware.input.InputSettings
import android.os.Handler
import android.util.ArrayMap
import android.util.Log
@@ -30,6 +31,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 +63,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 +76,10 @@
handler.post {
if (hasStarted) return@post
hasStarted = true
+ isInUsiSession =
+ inputManager.hasInputDevice {
+ it.isInternalStylusSource && isBatteryStateValid(it.batteryState)
+ }
addExistingStylusToMap()
inputManager.registerInputDeviceListener(this, handler)
@@ -177,7 +187,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()
}
@@ -215,12 +236,43 @@
*/
private fun onStylusUsed() {
if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return
- if (inputManager.isStylusEverUsed(context)) return
+ if (InputSettings.isStylusEverUsed(context)) return
- inputManager.setStylusEverUsed(context, true)
+ InputSettings.setStylusEverUsed(context, true)
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 +347,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/src/com/android/systemui/util/condition/ConditionalCoreStartable.java b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
index b41bca0..8d32a48 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java
@@ -43,11 +43,6 @@
@Override
public final void start() {
- if (mConditionSet == null || mConditionSet.isEmpty()) {
- onStart();
- return;
- }
-
mStartToken = mMonitor.addSubscription(
new Monitor.Subscription.Builder(allConditionsMet -> {
if (allConditionsMet) {
@@ -63,11 +58,6 @@
@Override
public final void onBootCompleted() {
- if (mConditionSet == null || mConditionSet.isEmpty()) {
- bootCompleted();
- return;
- }
-
mBootCompletedToken = mMonitor.addSubscription(
new Monitor.Subscription.Builder(allConditionsMet -> {
if (allConditionsMet) {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index ed2772a..2ef3511 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -165,6 +165,12 @@
android:exported="false"
android:permission="com.android.systemui.permission.SELF"
android:excludeFromRecents="true" />
+
+ <activity
+ android:name="com.android.systemui.screenshot.appclips.AppClipsActivityTest$AppClipsActivityTestable"
+ android:exported="false"
+ android:permission="com.android.systemui.permission.SELF"
+ android:excludeFromRecents="true" />
</application>
<instrumentation android:name="android.testing.TestableInstrumentation"
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index e8d50ca..badeb27 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -24,13 +24,19 @@
import android.os.PowerManager
import android.os.PowerManager.WAKE_REASON_BIOMETRIC
import android.os.UserHandle
-import android.provider.Settings
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.FakeSettings
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -41,20 +47,11 @@
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.io.PrintWriter
@SmallTest
class ActiveUnlockConfigTest : SysuiTestCase() {
- private val fakeWakeUri = Uri.Builder().appendPath("wake").build()
- private val fakeUnlockIntentUri = Uri.Builder().appendPath("unlock-intent").build()
- private val fakeBioFailUri = Uri.Builder().appendPath("bio-fail").build()
- private val fakeFaceErrorsUri = Uri.Builder().appendPath("face-errors").build()
- private val fakeFaceAcquiredUri = Uri.Builder().appendPath("face-acquired").build()
- private val fakeUnlockIntentBioEnroll = Uri.Builder().appendPath("unlock-intent-bio").build()
- private val fakeWakeupsConsideredUnlockIntents =
- Uri.Builder().appendPath("wakeups-considered-unlock-intent").build()
-
- @Mock
- private lateinit var secureSettings: SecureSettings
+ private lateinit var secureSettings: FakeSettings
@Mock
private lateinit var contentResolver: ContentResolver
@Mock
@@ -63,33 +60,20 @@
private lateinit var dumpManager: DumpManager
@Mock
private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var mockPrintWriter: PrintWriter
@Captor
private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
private lateinit var activeUnlockConfig: ActiveUnlockConfig
+ private var currentUser: Int = 0
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE))
- .thenReturn(fakeWakeUri)
- `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
- .thenReturn(fakeUnlockIntentUri)
- `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
- .thenReturn(fakeBioFailUri)
- `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS))
- .thenReturn(fakeFaceErrorsUri)
- `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
- .thenReturn(fakeFaceAcquiredUri)
- `when`(secureSettings.getUriFor(
- Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED))
- .thenReturn(fakeUnlockIntentBioEnroll)
- `when`(secureSettings.getUriFor(
- Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
- .thenReturn(fakeWakeupsConsideredUnlockIntents)
-
+ currentUser = KeyguardUpdateMonitor.getCurrentUser()
+ secureSettings = FakeSettings()
activeUnlockConfig = ActiveUnlockConfig(
handler,
secureSettings,
@@ -105,8 +89,6 @@
@Test
fun onWakeupSettingChanged() {
- verifyRegisterSettingObserver()
-
// GIVEN no active unlock settings enabled
assertFalse(
activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -114,9 +96,8 @@
)
// WHEN unlock on wake is allowed
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
- 0, 0)).thenReturn(1)
- updateSetting(fakeWakeUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_WAKE, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE))
// THEN active unlock triggers allowed on: wake, unlock-intent, and biometric failure
assertTrue(
@@ -135,8 +116,6 @@
@Test
fun onUnlockIntentSettingChanged() {
- verifyRegisterSettingObserver()
-
// GIVEN no active unlock settings enabled
assertFalse(
activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -144,9 +123,8 @@
)
// WHEN unlock on biometric failed is allowed
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
- 0, 0)).thenReturn(1)
- updateSetting(fakeUnlockIntentUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -159,21 +137,19 @@
@Test
fun onBioFailSettingChanged() {
- verifyRegisterSettingObserver()
-
// GIVEN no active unlock settings enabled and triggering unlock intent on biometric
// enrollment setting is disabled (empty string is disabled, null would use the default)
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
- 0)).thenReturn("")
- updateSetting(fakeUnlockIntentBioEnroll)
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, "", currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+ ))
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL))
// WHEN unlock on biometric failed is allowed
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
- 0, 0)).thenReturn(1)
- updateSetting(fakeBioFailUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -186,17 +162,14 @@
@Test
fun faceErrorSettingsChanged() {
- verifyRegisterSettingObserver()
-
// GIVEN unlock on biometric fail
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
- 0, 0)).thenReturn(1)
- updateSetting(fakeBioFailUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
// WHEN face error timeout (3), allow trigger active unlock
- `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
- 0)).thenReturn("3")
- updateSetting(fakeFaceAcquiredUri)
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_ON_FACE_ERRORS, "3", currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS))
// THEN active unlock triggers allowed on error TIMEOUT
assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
@@ -208,19 +181,17 @@
@Test
fun faceAcquiredSettingsChanged() {
- verifyRegisterSettingObserver()
-
// GIVEN unlock on biometric fail
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
- 0, 0)).thenReturn(1)
- updateSetting(fakeBioFailUri)
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, "1", currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
// WHEN face acquiredMsg DARK_GLASSESand MOUTH_COVERING are allowed to trigger
- `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
- 0)).thenReturn(
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
"${BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED}" +
- "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}")
- updateSetting(fakeFaceAcquiredUri)
+ "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}",
+ currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
// THEN active unlock triggers allowed on acquired messages DARK_GLASSES & MOUTH_COVERING
assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
@@ -236,23 +207,23 @@
@Test
fun triggerOnUnlockIntentWhenBiometricEnrolledNone() {
- verifyRegisterSettingObserver()
-
// GIVEN unlock on biometric fail
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
- 0, 0)).thenReturn(1)
- updateSetting(fakeBioFailUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
// GIVEN fingerprint and face are NOT enrolled
activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
- `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
`when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
// WHEN unlock intent is allowed when NO biometrics are enrolled (0)
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
- 0)).thenReturn("${ActiveUnlockConfig.BiometricType.NONE.intValue}")
- updateSetting(fakeUnlockIntentBioEnroll)
+
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ "${ActiveUnlockConfig.BiometricType.NONE.intValue}", currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+ ))
// THEN active unlock triggers allowed on unlock intent
assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -261,12 +232,9 @@
@Test
fun triggerOnUnlockIntentWhenBiometricEnrolledFingerprintOrFaceOnly() {
- verifyRegisterSettingObserver()
-
// GIVEN unlock on biometric fail
- `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
- 0, 0)).thenReturn(1)
- updateSetting(fakeBioFailUri)
+ secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
// GIVEN fingerprint and face are both enrolled
activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
@@ -275,12 +243,14 @@
// WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
// are enrolled
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
- 0)).thenReturn(
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
"${ActiveUnlockConfig.BiometricType.ANY_FACE.intValue}" +
- "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}")
- updateSetting(fakeUnlockIntentBioEnroll)
+ "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}",
+ currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+ ))
// THEN active unlock triggers NOT allowed on unlock intent
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -305,13 +275,12 @@
@Test
fun isWakeupConsideredUnlockIntent_singleValue() {
- verifyRegisterSettingObserver()
-
// GIVEN lift is considered an unlock intent
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
- 0)).thenReturn(PowerManager.WAKE_REASON_LIFT.toString())
- updateSetting(fakeWakeupsConsideredUnlockIntents)
+ secureSettings.putIntForUser(
+ ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
+ PowerManager.WAKE_REASON_LIFT,
+ currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
// THEN only WAKE_REASON_LIFT is considered an unlock intent
for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -325,17 +294,15 @@
@Test
fun isWakeupConsideredUnlockIntent_multiValue() {
- verifyRegisterSettingObserver()
-
// GIVEN lift and tap are considered an unlock intent
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
- 0)).thenReturn(
+ secureSettings.putStringForUser(
+ ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
PowerManager.WAKE_REASON_LIFT.toString() +
"|" +
- PowerManager.WAKE_REASON_TAP.toString()
+ PowerManager.WAKE_REASON_TAP.toString(),
+ currentUser
)
- updateSetting(fakeWakeupsConsideredUnlockIntents)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
// THEN WAKE_REASON_LIFT and WAKE_REASON TAP are considered an unlock intent
for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -354,13 +321,10 @@
@Test
fun isWakeupConsideredUnlockIntent_emptyValues() {
- verifyRegisterSettingObserver()
-
// GIVEN lift and tap are considered an unlock intent
- `when`(secureSettings.getStringForUser(
- Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
- 0)).thenReturn(" ")
- updateSetting(fakeWakeupsConsideredUnlockIntents)
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, " ",
+ currentUser)
+ updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS))
// THEN no wake up gestures are considered an unlock intent
for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
@@ -373,7 +337,23 @@
PowerManager.WAKE_REASON_UNFOLD_DEVICE))
}
+ @Test
+ fun dump_onUnlockIntentWhenBiometricEnrolled_invalidNum_noArrayOutOfBoundsException() {
+ // GIVEN an invalid input (-1)
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ "-1", currentUser)
+
+ // WHEN the setting updates
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+ ))
+
+ // THEN no exception thrown
+ activeUnlockConfig.dump(mockPrintWriter, emptyArray())
+ }
+
private fun updateSetting(uri: Uri) {
+ verifyRegisterSettingObserver()
settingsObserverCaptor.value.onChange(
false,
listOf(uri),
@@ -383,13 +363,17 @@
}
private fun verifyRegisterSettingObserver() {
- verifyRegisterSettingObserver(fakeWakeUri)
- verifyRegisterSettingObserver(fakeUnlockIntentUri)
- verifyRegisterSettingObserver(fakeBioFailUri)
- verifyRegisterSettingObserver(fakeFaceErrorsUri)
- verifyRegisterSettingObserver(fakeFaceAcquiredUri)
- verifyRegisterSettingObserver(fakeUnlockIntentBioEnroll)
- verifyRegisterSettingObserver(fakeWakeupsConsideredUnlockIntents)
+ verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
+ ))
+ verifyRegisterSettingObserver(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+ ))
}
private fun verifyRegisterSettingObserver(uri: Uri) {
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/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
index b9db9c4..b3329eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
@@ -32,6 +32,7 @@
import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Monitor;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -67,7 +68,6 @@
private ComplicationTypesUpdater mController;
- @Mock
private Monitor mMonitor;
@Before
@@ -75,6 +75,7 @@
MockitoAnnotations.initMocks(this);
when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>());
+ mMonitor = SelfExecutingMonitor.createInstance();
mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor,
mSecureSettings, mDreamOverlayStateController, mMonitor);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index 52aaea1..f6662d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -29,6 +29,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Monitor;
@@ -70,13 +71,13 @@
@Mock
private ComplicationLayoutParams mLayoutParams;
- @Mock
private Monitor mMonitor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
+ mMonitor = SelfExecutingMonitor.createInstance();
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 8534d4f..3312c43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -38,6 +38,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.view.LaunchableImageView;
+import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.controls.ControlsServiceInfo;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.controller.StructureInfo;
@@ -102,7 +103,6 @@
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
- @Mock
private Monitor mMonitor;
@Before
@@ -116,6 +116,8 @@
Optional.of(mControlsListingController));
when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE);
when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView);
+
+ mMonitor = SelfExecutingMonitor.createInstance();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
index 77ca958..ef62abf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
@@ -30,6 +30,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.condition.SelfExecutingMonitor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dreams.smartspace.DreamSmartspaceController;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
@@ -64,7 +65,6 @@
@Mock
private View mBcSmartspaceView;
- @Mock
private Monitor mMonitor;
private final Set<Condition> mPreconditions = new HashSet<>();
@@ -72,6 +72,7 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mMonitor = SelfExecutingMonitor.createInstance();
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index db18ba6..5bb8367 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -18,15 +18,19 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.app.StatusBarManager
+import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.pm.PackageManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.CameraGestureHelper
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -44,21 +48,28 @@
@Mock private lateinit var cameraGestureHelper: CameraGestureHelper
@Mock private lateinit var context: Context
@Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var userTracker: UserTracker
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: CameraQuickAffordanceConfig
+ private lateinit var testScope: TestScope
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- setLaunchable(true)
+ setLaunchable()
+ val testDispatcher = StandardTestDispatcher()
+ testScope = TestScope(testDispatcher)
underTest =
CameraQuickAffordanceConfig(
context,
packageManager,
- ) {
- cameraGestureHelper
- }
+ { cameraGestureHelper },
+ userTracker,
+ devicePolicyManager,
+ testDispatcher,
+ )
}
@Test
@@ -73,23 +84,57 @@
}
@Test
- fun `getPickerScreenState - default when launchable`() = runTest {
- setLaunchable(true)
+ fun `getPickerScreenState - default when launchable`() =
+ testScope.runTest {
+ setLaunchable(true)
- Truth.assertThat(underTest.getPickerScreenState())
- .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
- }
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+ }
@Test
- fun `getPickerScreenState - unavailable when not launchable`() = runTest {
- setLaunchable(false)
+ fun `getPickerScreenState - unavailable when camera app not installed`() =
+ testScope.runTest {
+ setLaunchable(isCameraAppInstalled = false)
- Truth.assertThat(underTest.getPickerScreenState())
- .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
- }
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
- private fun setLaunchable(isLaunchable: Boolean) {
+ @Test
+ fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+ testScope.runTest {
+ setLaunchable(isCameraDisabledByDeviceAdmin = true)
+
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ @Test
+ fun `getPickerScreenState - unavailable when secure camera disabled by admin`() =
+ testScope.runTest {
+ setLaunchable(isSecureCameraDisabledByDeviceAdmin = true)
+
+ Truth.assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ private fun setLaunchable(
+ isCameraAppInstalled: Boolean = true,
+ isCameraDisabledByDeviceAdmin: Boolean = false,
+ isSecureCameraDisabledByDeviceAdmin: Boolean = false,
+ ) {
whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
- .thenReturn(isLaunchable)
+ .thenReturn(isCameraAppInstalled)
+ whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId))
+ .thenReturn(isCameraDisabledByDeviceAdmin)
+ whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
+ .thenReturn(
+ if (isSecureCameraDisabledByDeviceAdmin) {
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
+ } else {
+ 0
+ }
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
index 5bd86bd..f1b9c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance
+import android.app.admin.DevicePolicyManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.ActivityIntentHelper
@@ -24,11 +25,14 @@
import com.android.systemui.camera.CameraIntentsWrapper
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -44,59 +48,94 @@
class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() {
@Mock private lateinit var activityIntentHelper: ActivityIntentHelper
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: VideoCameraQuickAffordanceConfig
+ private lateinit var userTracker: UserTracker
+ private lateinit var testScope: TestScope
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ val testDispatcher = StandardTestDispatcher()
+ testScope = TestScope(testDispatcher)
+ userTracker = FakeUserTracker()
underTest =
VideoCameraQuickAffordanceConfig(
context = context,
cameraIntents = CameraIntentsWrapper(context),
activityIntentHelper = activityIntentHelper,
- userTracker = FakeUserTracker(),
+ userTracker = userTracker,
+ devicePolicyManager = devicePolicyManager,
+ backgroundDispatcher = testDispatcher,
)
}
@Test
- fun `lockScreenState - visible when launchable`() = runTest {
- setLaunchable(true)
+ fun `lockScreenState - visible when launchable`() =
+ testScope.runTest {
+ setLaunchable()
- val lockScreenState = collectLastValue(underTest.lockScreenState)
+ val lockScreenState = collectLastValue(underTest.lockScreenState)
- assertThat(lockScreenState())
- .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
- }
+ assertThat(lockScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java)
+ }
@Test
- fun `lockScreenState - hidden when not launchable`() = runTest {
- setLaunchable(false)
+ fun `lockScreenState - hidden when app not installed on device`() =
+ testScope.runTest {
+ setLaunchable(isVideoCameraAppInstalled = false)
- val lockScreenState = collectLastValue(underTest.lockScreenState)
+ val lockScreenState = collectLastValue(underTest.lockScreenState)
- assertThat(lockScreenState())
- .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
- }
+ assertThat(lockScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+ }
@Test
- fun `getPickerScreenState - default when launchable`() = runTest {
- setLaunchable(true)
+ fun `lockScreenState - hidden when camera disabled by admin`() =
+ testScope.runTest {
+ setLaunchable(isCameraDisabledByAdmin = true)
- assertThat(underTest.getPickerScreenState())
- .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
- }
+ val lockScreenState = collectLastValue(underTest.lockScreenState)
+
+ assertThat(lockScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+ }
@Test
- fun `getPickerScreenState - unavailable when not launchable`() = runTest {
- setLaunchable(false)
+ fun `getPickerScreenState - default when launchable`() =
+ testScope.runTest {
+ setLaunchable()
- assertThat(underTest.getPickerScreenState())
- .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
- }
+ assertThat(underTest.getPickerScreenState())
+ .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java)
+ }
- private fun setLaunchable(isLaunchable: Boolean) {
+ @Test
+ fun `getPickerScreenState - unavailable when app not installed on device`() =
+ testScope.runTest {
+ setLaunchable(isVideoCameraAppInstalled = false)
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ @Test
+ fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+ testScope.runTest {
+ setLaunchable(isCameraDisabledByAdmin = true)
+
+ assertThat(underTest.getPickerScreenState())
+ .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+ }
+
+ private fun setLaunchable(
+ isVideoCameraAppInstalled: Boolean = true,
+ isCameraDisabledByAdmin: Boolean = false,
+ ) {
whenever(
activityIntentHelper.getTargetActivityInfo(
any(),
@@ -105,11 +144,13 @@
)
)
.thenReturn(
- if (isLaunchable) {
+ if (isVideoCameraAppInstalled) {
mock()
} else {
null
}
)
+ whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId))
+ .thenReturn(isCameraDisabledByAdmin)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 997198e..a72634b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -61,7 +61,6 @@
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -69,6 +68,8 @@
import org.mockito.Mock
import org.mockito.Mockito.floatThat
import org.mockito.Mockito.mock
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -107,7 +108,6 @@
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor
lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
- @Captor lateinit var newConfig: ArgumentCaptor<Configuration>
@Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
@Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -150,7 +150,6 @@
MediaPlayerData.clear()
}
- @Ignore("b/253229241")
@Test
fun testPlayerOrdering() {
// Test values: key, data, last active time
@@ -327,7 +326,6 @@
}
}
- @Ignore("b/253229241")
@Test
fun testOrderWithSmartspace_prioritized() {
testPlayerOrdering()
@@ -335,7 +333,7 @@
// If smartspace is prioritized
MediaPlayerData.addMediaRecommendation(
SMARTSPACE_KEY,
- EMPTY_SMARTSPACE_MEDIA_DATA,
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
panel,
true,
clock
@@ -345,7 +343,6 @@
assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec)
}
- @Ignore("b/253229241")
@Test
fun testOrderWithSmartspace_prioritized_updatingVisibleMediaPlayers() {
testPlayerOrdering()
@@ -362,7 +359,6 @@
assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(2).isSsMediaRec)
}
- @Ignore("b/253229241")
@Test
fun testOrderWithSmartspace_notPrioritized() {
testPlayerOrdering()
@@ -370,7 +366,7 @@
// If smartspace is not prioritized
MediaPlayerData.addMediaRecommendation(
SMARTSPACE_KEY,
- EMPTY_SMARTSPACE_MEDIA_DATA,
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
panel,
false,
clock
@@ -381,7 +377,6 @@
assertTrue(MediaPlayerData.playerKeys().elementAt(idx).isSsMediaRec)
}
- @Ignore("b/253229241")
@Test
fun testPlayingExistingMediaPlayerFromCarousel_visibleMediaPlayersNotUpdated() {
testPlayerOrdering()
@@ -419,7 +414,6 @@
)
}
- @Ignore("b/253229241")
@Test
fun testSwipeDismiss_logged() {
mediaCarouselController.mediaCarouselScrollHandler.dismissCallback.invoke()
@@ -427,7 +421,6 @@
verify(logger).logSwipeDismiss()
}
- @Ignore("b/253229241")
@Test
fun testSettingsButton_logged() {
mediaCarouselController.settingsButton.callOnClick()
@@ -435,18 +428,16 @@
verify(logger).logCarouselSettings()
}
- @Ignore("b/253229241")
@Test
fun testLocationChangeQs_logged() {
mediaCarouselController.onDesiredLocationChanged(
- MediaHierarchyManager.LOCATION_QS,
+ LOCATION_QS,
mediaHostState,
animate = false
)
- verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QS)
+ verify(logger).logCarouselPosition(LOCATION_QS)
}
- @Ignore("b/253229241")
@Test
fun testLocationChangeQqs_logged() {
mediaCarouselController.onDesiredLocationChanged(
@@ -457,7 +448,6 @@
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS)
}
- @Ignore("b/253229241")
@Test
fun testLocationChangeLockscreen_logged() {
mediaCarouselController.onDesiredLocationChanged(
@@ -468,7 +458,6 @@
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN)
}
- @Ignore("b/253229241")
@Test
fun testLocationChangeDream_logged() {
mediaCarouselController.onDesiredLocationChanged(
@@ -479,7 +468,6 @@
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY)
}
- @Ignore("b/253229241")
@Test
fun testRecommendationRemoved_logged() {
val packageName = "smartspace package"
@@ -493,7 +481,6 @@
verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
}
- @Ignore("b/253229241")
@Test
fun testMediaLoaded_ScrollToActivePlayer() {
listener.value.onMediaDataLoaded(
@@ -551,7 +538,6 @@
)
}
- @Ignore("b/253229241")
@Test
fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
listener.value.onSmartspaceMediaDataLoaded(
@@ -595,7 +581,6 @@
assertEquals(playerIndex, 0)
}
- @Ignore("b/253229241")
@Test
fun testRecommendationRemovedWhileNotVisible_updateHostVisibility() {
var result = false
@@ -607,7 +592,6 @@
assertEquals(true, result)
}
- @Ignore("b/253229241")
@Test
fun testRecommendationRemovedWhileVisible_thenReorders_updateHostVisibility() {
var result = false
@@ -621,7 +605,6 @@
assertEquals(true, result)
}
- @Ignore("b/253229241")
@Test
fun testGetCurrentVisibleMediaContentIntent() {
val clickIntent1 = mock(PendingIntent::class.java)
@@ -668,7 +651,6 @@
assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2)
}
- @Ignore("b/253229241")
@Test
fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
val delta = 0.0001F
@@ -690,7 +672,6 @@
verify(pageIndicator).alpha = floatThat { abs(it - 1.0F) < delta }
}
- @Ignore("b/253229241")
@Test
fun testOnConfigChanged_playersAreAddedBack() {
listener.value.onMediaDataLoaded(
@@ -716,7 +697,7 @@
val playersSize = MediaPlayerData.players().size
- configListener.value.onConfigChanged(capture(newConfig))
+ configListener.value.onConfigChanged(Configuration())
assertEquals(playersSize, MediaPlayerData.players().size)
assertEquals(
@@ -796,4 +777,59 @@
job.cancel()
}
+
+ @Test
+ fun testInvisibleToUserAndExpanded_playersNotListening() {
+ // Add players to carousel.
+ testPlayerOrdering()
+
+ // Make the carousel visible to user in expanded layout.
+ mediaCarouselController.currentlyExpanded = true
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+ // panel is the player for each MediaPlayerData.
+ // Verify that seekbar listening attribute in media control panel is set to true.
+ verify(panel, times(MediaPlayerData.players().size)).listening = true
+
+ // Make the carousel invisible to user.
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = false
+
+ // panel is the player for each MediaPlayerData.
+ // Verify that seekbar listening attribute in media control panel is set to false.
+ verify(panel, times(MediaPlayerData.players().size)).listening = false
+ }
+
+ @Test
+ fun testVisibleToUserAndExpanded_playersListening() {
+ // Add players to carousel.
+ testPlayerOrdering()
+
+ // Make the carousel visible to user in expanded layout.
+ mediaCarouselController.currentlyExpanded = true
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+ // panel is the player for each MediaPlayerData.
+ // Verify that seekbar listening attribute in media control panel is set to true.
+ verify(panel, times(MediaPlayerData.players().size)).listening = true
+ }
+
+ @Test
+ fun testUMOCollapsed_playersNotListening() {
+ // Add players to carousel.
+ testPlayerOrdering()
+
+ // Make the carousel in collapsed layout.
+ mediaCarouselController.currentlyExpanded = false
+
+ // panel is the player for each MediaPlayerData.
+ // Verify that seekbar listening attribute in media control panel is set to false.
+ verify(panel, times(MediaPlayerData.players().size)).listening = false
+
+ // Make the carousel visible to user.
+ reset(panel)
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true
+
+ // Verify that seekbar listening attribute in media control panel is set to false.
+ verify(panel, times(MediaPlayerData.players().size)).listening = false
+ }
}
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/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
new file mode 100644
index 0000000..d828e51
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.screenshot.appclips;
+
+import static android.app.Activity.RESULT_OK;
+
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.testing.AndroidTestingRunner;
+import android.widget.ImageView;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.intercepting.SingleActivityFactory;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.screenshot.AppClipsActivity;
+import com.android.systemui.screenshot.AppClipsTrampolineActivity;
+import com.android.systemui.screenshot.AppClipsViewModel;
+import com.android.systemui.settings.UserTracker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.BiConsumer;
+
+
+@RunWith(AndroidTestingRunner.class)
+public final class AppClipsActivityTest extends SysuiTestCase {
+
+ private static final int TEST_UID = 42;
+ private static final int TEST_USER_ID = 43;
+ private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ private static final String TEST_URI_STRING = "www.test-uri.com";
+ private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
+ private static final BiConsumer<Integer, Bundle> FAKE_CONSUMER = (unUsed1, unUsed2) -> {};
+ private static final String TEST_CALLING_PACKAGE = "test-calling-package";
+
+ @Mock
+ private AppClipsViewModel.Factory mViewModelFactory;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private UserTracker mUserTracker;
+ @Mock
+ private UiEventLogger mUiEventLogger;
+ @Mock
+ private AppClipsViewModel mViewModel;
+
+ private MutableLiveData<Bitmap> mScreenshotLiveData;
+ private MutableLiveData<Uri> mResultLiveData;
+ private AppClipsActivity mActivity;
+
+ // Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks.
+ private final SingleActivityFactory<AppClipsActivityTestable> mFactory =
+ new SingleActivityFactory<>(AppClipsActivityTestable.class) {
+ @Override
+ protected AppClipsActivityTestable create(Intent unUsed) {
+ return new AppClipsActivityTestable(mViewModelFactory, mPackageManager,
+ mUserTracker, mUiEventLogger);
+ }
+ };
+
+ @Rule
+ public final ActivityTestRule<AppClipsActivityTestable> mActivityRule =
+ new ActivityTestRule<>(mFactory, false, false);
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+
+ mScreenshotLiveData = new MutableLiveData<>();
+ mResultLiveData = new MutableLiveData<>();
+ MutableLiveData<Integer> errorLiveData = new MutableLiveData<>();
+
+ when(mViewModelFactory.create(any(Class.class))).thenReturn(mViewModel);
+ when(mViewModel.getScreenshot()).thenReturn(mScreenshotLiveData);
+ when(mViewModel.getResultLiveData()).thenReturn(mResultLiveData);
+ when(mViewModel.getErrorLiveData()).thenReturn(errorLiveData);
+ when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
+
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = TEST_UID;
+ when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
+ any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo);
+
+ doAnswer(invocation -> {
+ runOnMainThread(() -> mScreenshotLiveData.setValue(TEST_BITMAP));
+ return null;
+ }).when(mViewModel).performScreenshot();
+ doAnswer(invocation -> {
+ runOnMainThread(() -> mResultLiveData.setValue(TEST_URI));
+ return null;
+ }).when(mViewModel).saveScreenshotThenFinish(any(Drawable.class), any(Rect.class));
+ }
+
+ @After
+ public void tearDown() {
+ mActivityRule.finishActivity();
+ }
+
+ @Test
+ public void appClipsLaunched_screenshotDisplayed() {
+ launchActivity();
+
+ assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
+ }
+
+ @Test
+ public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
+ ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
+ assertThat(resultCode).isEqualTo(RESULT_OK);
+ assertThat(
+ data.getParcelable(AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI, Uri.class))
+ .isEqualTo(TEST_URI);
+ assertThat(data.getInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE))
+ .isEqualTo(Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
+ });
+
+ launchActivity(resultReceiver);
+ runOnMainThread(() -> mActivity.findViewById(R.id.save).performClick());
+ waitForIdleSync();
+
+ assertThat(mActivity.isFinishing()).isTrue();
+ verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_ACCEPTED, TEST_UID, TEST_CALLING_PACKAGE);
+ }
+
+ @Test
+ public void screenshotDisplayed_userDeclined() {
+ ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
+ assertThat(resultCode).isEqualTo(RESULT_OK);
+ assertThat(data.getInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE))
+ .isEqualTo(Intent.CAPTURE_CONTENT_FOR_NOTE_USER_CANCELED);
+ assertThat(data.keySet().contains(AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI))
+ .isFalse();
+ });
+
+ launchActivity(resultReceiver);
+ runOnMainThread(() -> mActivity.findViewById(R.id.cancel).performClick());
+ waitForIdleSync();
+
+ assertThat(mActivity.isFinishing()).isTrue();
+ verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_CANCELLED, TEST_UID, TEST_CALLING_PACKAGE);
+ }
+
+ private void launchActivity() {
+ launchActivity(createResultReceiver(FAKE_CONSUMER));
+ }
+
+ private void launchActivity(ResultReceiver resultReceiver) {
+ Intent intent = new Intent()
+ .putExtra(AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER, resultReceiver)
+ .putExtra(AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME,
+ TEST_CALLING_PACKAGE);
+
+ mActivity = mActivityRule.launchActivity(intent);
+ waitForIdleSync();
+ }
+
+ private ResultReceiver createResultReceiver(
+ BiConsumer<Integer, Bundle> resultReceiverConsumer) {
+ ResultReceiver testReceiver = new ResultReceiver(mContext.getMainThreadHandler()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ resultReceiverConsumer.accept(resultCode, resultData);
+ }
+ };
+
+ Parcel parcel = Parcel.obtain();
+ testReceiver.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ testReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return testReceiver;
+ }
+
+ private void runOnMainThread(Runnable runnable) {
+ mContext.getMainExecutor().execute(runnable);
+ }
+
+ public static class AppClipsActivityTestable extends AppClipsActivity {
+
+ public AppClipsActivityTestable(AppClipsViewModel.Factory viewModelFactory,
+ PackageManager packageManager,
+ UserTracker userTracker,
+ UiEventLogger uiEventLogger) {
+ super(viewModelFactory, packageManager, userTracker, uiEventLogger);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
index 6e8f5fe..ab321f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
@@ -76,7 +76,7 @@
}
@Test
- public void bubblesPresent_screenshotFailed_ShouldReturnNull() throws RemoteException {
+ public void bubblesPresent_screenshotFailed_shouldReturnNull() throws RemoteException {
when(mBubblesOptional.isEmpty()).thenReturn(false);
when(mBubblesOptional.get()).thenReturn(mBubbles);
when(mBubbles.getScreenshotExcludingBubble(DEFAULT_DISPLAY)).thenReturn(mScreenshotSync);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 295d127..e40c49b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -25,23 +25,25 @@
import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
-import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
-import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -51,12 +53,15 @@
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.intercepting.SingleActivityFactory;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.notetask.NoteTaskController;
import com.android.systemui.screenshot.AppClipsTrampolineActivity;
+import com.android.systemui.screenshot.ScreenshotEvent;
+import com.android.systemui.settings.UserTracker;
import com.android.wm.shell.bubbles.Bubbles;
import org.junit.After;
@@ -74,7 +79,9 @@
private static final String TEST_URI_STRING = "www.test-uri.com";
private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
- private static final int TIME_OUT = 5000;
+ private static final int TEST_UID = 42;
+ private static final int TEST_USER_ID = 43;
+ private static final String TEST_CALLING_PACKAGE = "test-calling-package";
@Mock
private DevicePolicyManager mDevicePolicyManager;
@@ -86,6 +93,12 @@
private Bubbles mBubbles;
@Mock
private NoteTaskController mNoteTaskController;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private UserTracker mUserTracker;
+ @Mock
+ private UiEventLogger mUiEventLogger;
@Main
private Handler mMainHandler;
@@ -96,7 +109,8 @@
@Override
protected AppClipsTrampolineActivityTestable create(Intent unUsed) {
return new AppClipsTrampolineActivityTestable(mDevicePolicyManager,
- mFeatureFlags, mOptionalBubbles, mNoteTaskController, mMainHandler);
+ mFeatureFlags, mOptionalBubbles, mNoteTaskController, mPackageManager,
+ mUserTracker, mUiEventLogger, mMainHandler);
}
};
@@ -104,41 +118,36 @@
public final ActivityTestRule<AppClipsTrampolineActivityTestable> mActivityRule =
new ActivityTestRule<>(mFactory, false, false);
- private Context mContext;
private Intent mActivityIntent;
private ComponentName mExpectedComponentName;
- private Intent mKillAppClipsActivityBroadcast;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = getContext();
mMainHandler = mContext.getMainThreadHandler();
mActivityIntent = new Intent(mContext, AppClipsTrampolineActivityTestable.class);
mExpectedComponentName = ComponentName.unflattenFromString(
mContext.getString(
R.string.config_screenshotAppClipsActivityComponent));
- mKillAppClipsActivityBroadcast = new Intent(ACTION_FINISH_FROM_TRAMPOLINE)
- .setComponent(mExpectedComponentName)
- .setPackage(mExpectedComponentName.getPackageName());
}
@After
public void tearDown() {
- mContext.sendBroadcast(mKillAppClipsActivityBroadcast, PERMISSION_SELF);
mActivityRule.finishActivity();
}
@Test
- public void configComponentName_shouldResolve() {
+ public void appClipsActivityConfig_shouldBeConfigured() {
// Verify component name is setup - has package and class name.
assertThat(mExpectedComponentName).isNotNull();
assertThat(mExpectedComponentName.getPackageName()).isNotEmpty();
assertThat(mExpectedComponentName.getClassName()).isNotEmpty();
+ }
- // Verify an intent when launched with above component resolves to the same component to
- // confirm that component from above is available in framework.
+ @Test
+ public void configComponentName_shouldResolve() {
+ // Verify an intent when launched with configured component resolves to activity.
Intent appClipsActivityIntent = new Intent();
appClipsActivityIntent.setComponent(mExpectedComponentName);
ResolveInfo resolveInfo = getContext().getPackageManager().resolveActivity(
@@ -205,7 +214,8 @@
}
@Test
- public void startAppClipsActivity_userCanceled_shouldReturnUserCanceled() {
+ public void startAppClipsActivity_userCanceled_shouldReturnUserCanceled()
+ throws NameNotFoundException {
mockToSatisfyAllPrerequisites();
AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent);
@@ -224,7 +234,8 @@
}
@Test
- public void startAppClipsActivity_shouldReturnSuccess() {
+ public void startAppClipsActivity_shouldReturnSuccess()
+ throws NameNotFoundException {
mockToSatisfyAllPrerequisites();
AppClipsTrampolineActivityTestable activity = mActivityRule.launchActivity(mActivityIntent);
@@ -243,12 +254,31 @@
assertThat(actualResult.getResultData().getData()).isEqualTo(TEST_URI);
}
- private void mockToSatisfyAllPrerequisites() {
+ @Test
+ public void startAppClipsActivity_shouldLogUiEvent()
+ throws NameNotFoundException {
+ mockToSatisfyAllPrerequisites();
+
+ mActivityRule.launchActivity(mActivityIntent);
+ waitForIdleSync();
+
+ verify(mUiEventLogger).log(ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID,
+ TEST_CALLING_PACKAGE);
+ }
+
+ private void mockToSatisfyAllPrerequisites() throws NameNotFoundException {
when(mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)).thenReturn(true);
when(mOptionalBubbles.isEmpty()).thenReturn(false);
when(mOptionalBubbles.get()).thenReturn(mBubbles);
when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
+ when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
+
+ ApplicationInfo testApplicationInfo = new ApplicationInfo();
+ testApplicationInfo.uid = TEST_UID;
+ when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
+ any(ApplicationInfoFlags.class),
+ eq(TEST_USER_ID))).thenReturn(testApplicationInfo);
}
public static final class AppClipsTrampolineActivityTestable extends
@@ -258,8 +288,22 @@
FeatureFlags flags,
Optional<Bubbles> optionalBubbles,
NoteTaskController noteTaskController,
+ PackageManager packageManager,
+ UserTracker userTracker,
+ UiEventLogger uiEventLogger,
@Main Handler mainHandler) {
- super(devicePolicyManager, flags, optionalBubbles, noteTaskController, mainHandler);
+ super(devicePolicyManager, flags, optionalBubbles, noteTaskController, packageManager,
+ userTracker, uiEventLogger, mainHandler);
+ }
+
+ @Override
+ public String getCallingPackage() {
+ return TEST_CALLING_PACKAGE;
+ }
+
+ @Override
+ public void startActivity(Intent unUsed) {
+ // Ignore this intent to avoid App Clips screenshot editing activity from starting.
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index 9eccbb6..aa1636d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -249,6 +249,21 @@
}
@Test
+ public void addCallback_preCondition_noConditions_reportAllConditionsMet() {
+ final Monitor
+ monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(mCondition1)));
+ final Monitor.Callback callback = mock(
+ Monitor.Callback.class);
+
+ monitor.addSubscription(new Monitor.Subscription.Builder(callback).build());
+ mExecutor.runAllReady();
+ verify(callback, never()).onConditionsChanged(true);
+ mCondition1.fakeUpdateCondition(true);
+ mExecutor.runAllReady();
+ verify(callback).onConditionsChanged(true);
+ }
+
+ @Test
public void removeCallback_noFailureOnDoubleRemove() {
final Condition condition = mock(
Condition.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 673e559..3853b99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -896,21 +896,31 @@
// Subscription 1
private const val SUB_1_ID = 1
+ private val GROUP_1 = ParcelUuid(UUID.randomUUID())
private val SUB_1 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_1_ID)
- whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+ whenever(it.groupUuid).thenReturn(GROUP_1)
}
- private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ private val MODEL_1 =
+ SubscriptionModel(
+ subscriptionId = SUB_1_ID,
+ groupUuid = GROUP_1,
+ )
// Subscription 2
private const val SUB_2_ID = 2
+ private val GROUP_2 = ParcelUuid(UUID.randomUUID())
private val SUB_2 =
mock<SubscriptionInfo>().also {
whenever(it.subscriptionId).thenReturn(SUB_2_ID)
- whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+ whenever(it.groupUuid).thenReturn(GROUP_2)
}
- private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ private val MODEL_2 =
+ SubscriptionModel(
+ subscriptionId = SUB_2_ID,
+ groupUuid = GROUP_2,
+ )
// Subs 3 and 4 are considered to be in the same group ------------------------------------
private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index f8a9783..bbca001 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+import android.os.ParcelUuid
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
@@ -34,6 +35,7 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -104,6 +106,21 @@
job.cancel()
}
+ // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
+ @Test
+ fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
+ testScope.runTest {
+ connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+ connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+
+ job.cancel()
+ }
+
@Test
fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
testScope.runTest {
@@ -118,10 +135,50 @@
}
@Test
- fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() =
+ fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
testScope.runTest {
connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP))
+
+ job.cancel()
+ }
+
+ @Test
+ fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
+ testScope.runTest {
+ val (sub1, sub2) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
+ opportunistic = Pair(true, true),
+ grouped = false,
+ )
+ connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+ connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(listOf(sub1, sub2))
+
+ job.cancel()
+ }
+
+ @Test
+ fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
+ testScope.runTest {
+ val (sub3, sub4) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+ opportunistic = Pair(true, true),
+ grouped = true,
+ )
+ connectionsRepository.setSubscriptions(listOf(sub3, sub4))
+ connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(false)
@@ -129,15 +186,21 @@
val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
// Filtered subscriptions should show the active one when the config is false
- assertThat(latest).isEqualTo(listOf(SUB_3_OPP))
+ assertThat(latest).isEqualTo(listOf(sub3))
job.cancel()
}
@Test
- fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() =
+ fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
testScope.runTest {
- connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
+ val (sub3, sub4) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+ opportunistic = Pair(true, true),
+ grouped = true,
+ )
+ connectionsRepository.setSubscriptions(listOf(sub3, sub4))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(false)
@@ -146,15 +209,21 @@
val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
// Filtered subscriptions should show the active one when the config is false
- assertThat(latest).isEqualTo(listOf(SUB_4_OPP))
+ assertThat(latest).isEqualTo(listOf(sub4))
job.cancel()
}
@Test
- fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() =
+ fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
testScope.runTest {
- connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+ val (sub1, sub3) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+ opportunistic = Pair(false, true),
+ grouped = true,
+ )
+ connectionsRepository.setSubscriptions(listOf(sub1, sub3))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(true)
@@ -164,15 +233,21 @@
// Filtered subscriptions should show the primary (non-opportunistic) if the config is
// true
- assertThat(latest).isEqualTo(listOf(SUB_1))
+ assertThat(latest).isEqualTo(listOf(sub1))
job.cancel()
}
@Test
- fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() =
+ fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
testScope.runTest {
- connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+ val (sub1, sub3) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+ opportunistic = Pair(false, true),
+ grouped = true,
+ )
+ connectionsRepository.setSubscriptions(listOf(sub1, sub3))
connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
.thenReturn(true)
@@ -182,7 +257,7 @@
// Filtered subscriptions should show the primary (non-opportunistic) if the config is
// true
- assertThat(latest).isEqualTo(listOf(SUB_1))
+ assertThat(latest).isEqualTo(listOf(sub1))
job.cancel()
}
@@ -642,6 +717,33 @@
job.cancel()
}
+ /**
+ * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
+ * flow.
+ */
+ private fun createSubscriptionPair(
+ subscriptionIds: Pair<Int, Int>,
+ opportunistic: Pair<Boolean, Boolean> = Pair(false, false),
+ grouped: Boolean = false,
+ ): Pair<SubscriptionModel, SubscriptionModel> {
+ val groupUuid = if (grouped) ParcelUuid(UUID.randomUUID()) else null
+ val sub1 =
+ SubscriptionModel(
+ subscriptionId = subscriptionIds.first,
+ isOpportunistic = opportunistic.first,
+ groupUuid = groupUuid,
+ )
+
+ val sub2 =
+ SubscriptionModel(
+ subscriptionId = subscriptionIds.second,
+ isOpportunistic = opportunistic.second,
+ groupUuid = groupUuid,
+ )
+
+ return Pair(sub1, sub2)
+ }
+
companion object {
private val tableLogBuffer =
TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
@@ -655,11 +757,21 @@
private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer)
private const val SUB_3_ID = 3
- private val SUB_3_OPP = SubscriptionModel(subscriptionId = SUB_3_ID, isOpportunistic = true)
+ private val SUB_3_OPP =
+ SubscriptionModel(
+ subscriptionId = SUB_3_ID,
+ isOpportunistic = true,
+ groupUuid = ParcelUuid(UUID.randomUUID()),
+ )
private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer)
private const val SUB_4_ID = 4
- private val SUB_4_OPP = SubscriptionModel(subscriptionId = SUB_4_ID, isOpportunistic = true)
+ private val SUB_4_OPP =
+ SubscriptionModel(
+ subscriptionId = SUB_4_ID,
+ isOpportunistic = true,
+ groupUuid = ParcelUuid(UUID.randomUUID()),
+ )
private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer)
}
}
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..48a2e09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -19,10 +19,16 @@
import android.bluetooth.BluetoothDevice
import android.hardware.BatteryState
import android.hardware.input.InputManager
+import android.hardware.input.InputSettings
import android.os.Handler
import android.testing.AndroidTestingRunner
import android.view.InputDevice
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.ExtendedMockito.never
+import com.android.dx.mockito.inline.extended.ExtendedMockito.times
+import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
@@ -30,18 +36,17 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import java.util.concurrent.Executor
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
+import org.mockito.quality.Strictness
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -67,11 +72,17 @@
@Mock lateinit var otherStylusBatteryCallback: StylusManager.StylusBatteryCallback
+ private lateinit var mockitoSession: StaticMockitoSession
private lateinit var stylusManager: StylusManager
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ mockitoSession =
+ mockitoSession()
+ .mockStatic(InputSettings::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
whenever(handler.post(any())).thenAnswer {
(it.arguments[0] as Runnable).run()
@@ -96,23 +107,32 @@
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)
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(STYLUS_DEVICE_ID))
- whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(false)
whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(bluetoothDevice)
whenever(bluetoothDevice.address).thenReturn(STYLUS_BT_ADDRESS)
whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(true)
+ whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(false)
+
stylusManager.startListener()
stylusManager.registerCallback(stylusCallback)
stylusManager.registerBatteryCallback(stylusBatteryCallback)
clearInvocations(inputManager)
}
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
@Test
fun startListener_hasNotStarted_registersInputDeviceListener() {
stylusManager =
@@ -206,8 +226,7 @@
@Test
fun onInputDeviceAdded_btStylus_firstUsed_setsFlag() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
-
- verify(inputManager, times(1)).setStylusEverUsed(mContext, true)
+ verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1))
}
@Test
@@ -481,7 +500,7 @@
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
- verify(inputManager).setStylusEverUsed(mContext, true)
+ verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1))
}
@Test
@@ -494,13 +513,55 @@
}
@Test
- fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() {
- whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(true)
+ fun onBatteryStateChanged_batteryPresent_notInUsiSession_logsSessionStart() {
whenever(batteryState.isPresent).thenReturn(true)
stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
- verify(inputManager, never()).setStylusEverUsed(mContext, true)
+ 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(InputSettings.isStylusEverUsed(mContext)).thenReturn(true)
+
+ whenever(batteryState.isPresent).thenReturn(true)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify({ InputSettings.setStylusEverUsed(mContext, true) }, never())
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
index 5ef62c1..b367a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
@@ -60,6 +60,11 @@
mCallback = callback;
}
+ public FakeConditionalCoreStartable(Monitor monitor, Callback callback) {
+ super(monitor);
+ mCallback = callback;
+ }
+
@Override
protected void onStart() {
mCallback.onStart();
@@ -122,6 +127,31 @@
verify(mMonitor).removeSubscription(mSubscriptionToken);
}
+ @Test
+ public void testOnStartCallbackWithNoConditions() {
+ final CoreStartable coreStartable =
+ new FakeConditionalCoreStartable(mMonitor,
+ mCallback);
+
+ when(mMonitor.addSubscription(any())).thenReturn(mSubscriptionToken);
+ coreStartable.start();
+
+ final ArgumentCaptor<Monitor.Subscription> subscriptionCaptor = ArgumentCaptor.forClass(
+ Monitor.Subscription.class);
+ verify(mMonitor).addSubscription(subscriptionCaptor.capture());
+
+ final Monitor.Subscription subscription = subscriptionCaptor.getValue();
+
+ assertThat(subscription.getConditions()).isEmpty();
+
+ verify(mCallback, never()).onStart();
+
+ subscription.getCallback().onConditionsChanged(true);
+
+ verify(mCallback).onStart();
+ verify(mMonitor).removeSubscription(mSubscriptionToken);
+ }
+
/**
* Verifies that {@link ConditionalCoreStartable#bootCompleted()} ()} is predicated on
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java
new file mode 100644
index 0000000..7ee05d0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.condition;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+/**
+ * {@link SelfExecutingMonitor} creates a monitor that independently executes its logic through
+ * a {@link FakeExecutor}, which is ran at when a subscription is added and removed.
+ */
+public class SelfExecutingMonitor extends Monitor {
+ private final FakeExecutor mExecutor;
+
+ /**
+ * Default constructor that allows specifying the FakeExecutor to use.
+ */
+ public SelfExecutingMonitor(FakeExecutor executor) {
+ super(executor);
+ mExecutor = executor;
+ }
+
+ @Override
+ public Subscription.Token addSubscription(@NonNull Subscription subscription) {
+ final Subscription.Token result = super.addSubscription(subscription);
+ mExecutor.runAllReady();
+ return result;
+ }
+
+ @Override
+ public void removeSubscription(@NonNull Subscription.Token token) {
+ super.removeSubscription(token);
+ mExecutor.runNextReady();
+ }
+
+ /**
+ * Creates a {@link SelfExecutingMonitor} with a self-managed {@link FakeExecutor}. Use only
+ * for cases where condition state only will be set at when a subscription is added.
+ */
+ public static SelfExecutingMonitor createInstance() {
+ final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ final FakeExecutor mExecutor = new FakeExecutor(mFakeSystemClock);
+ return new SelfExecutingMonitor(mExecutor);
+ }
+}
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/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ec69306..4d5baaf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -487,6 +487,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.function.Supplier;
public class ActivityManagerService extends IActivityManager.Stub
@@ -6452,6 +6453,44 @@
return entry == null ? null : entry.second;
}
+ private static class GetBackgroundStartPrivilegesFunctor implements Consumer<ProcessRecord> {
+ private BackgroundStartPrivileges mBackgroundStartPrivileges =
+ BackgroundStartPrivileges.NONE;
+ private int mUid;
+
+ void prepare(int uid) {
+ mUid = uid;
+ mBackgroundStartPrivileges = BackgroundStartPrivileges.NONE;
+ }
+
+ @NonNull
+ BackgroundStartPrivileges getResult() {
+ return mBackgroundStartPrivileges;
+ }
+
+ public void accept(ProcessRecord pr) {
+ if (pr.uid == mUid) {
+ mBackgroundStartPrivileges =
+ mBackgroundStartPrivileges.merge(pr.getBackgroundStartPrivileges());
+ }
+ }
+ }
+
+ private final GetBackgroundStartPrivilegesFunctor mGetBackgroundStartPrivilegesFunctor =
+ new GetBackgroundStartPrivilegesFunctor();
+
+ /**
+ * Returns the current complete {@link BackgroundStartPrivileges} of the UID.
+ */
+ @NonNull
+ private BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
+ synchronized (mProcLock) {
+ mGetBackgroundStartPrivilegesFunctor.prepare(uid);
+ mProcessList.forEachLruProcessesLOSP(false, mGetBackgroundStartPrivilegesFunctor);
+ return mGetBackgroundStartPrivilegesFunctor.getResult();
+ }
+ }
+
/**
* @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
* the allowlist
@@ -16884,13 +16923,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
@@ -17850,6 +17890,11 @@
return mConstants.mFlagBackgroundActivityStartsEnabled;
}
+ @Override
+ public BackgroundStartPrivileges getBackgroundStartPrivileges(int uid) {
+ return ActivityManagerService.this.getBackgroundStartPrivileges(uid);
+ }
+
public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
ActivityManagerService.this.reportGlobalUsageEvent(keyguardShowing
? UsageEvents.Event.KEYGUARD_SHOWN
@@ -18489,6 +18534,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/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a707202..fa3f684 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -20,6 +20,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
@@ -341,6 +342,24 @@
private boolean mInFullBackup;
/**
+ * A set of tokens that currently contribute to this process being temporarily allowed
+ * to start certain components (eg. activities or foreground services) even if it's not
+ * in the foreground.
+ */
+ @GuardedBy("mBackgroundStartPrivileges")
+ private final ArrayMap<Binder, BackgroundStartPrivileges> mBackgroundStartPrivileges =
+ new ArrayMap<>();
+
+ /**
+ * The merged BackgroundStartPrivileges based on what's in {@link #mBackgroundStartPrivileges}.
+ * This is lazily generated using {@link #getBackgroundStartPrivileges()}.
+ */
+ @Nullable
+ @GuardedBy("mBackgroundStartPrivileges")
+ private BackgroundStartPrivileges mBackgroundStartPrivilegesMerged =
+ BackgroundStartPrivileges.NONE;
+
+ /**
* Controller for driving the process state on the window manager side.
*/
private final WindowProcessController mWindowProcessController;
@@ -1325,11 +1344,50 @@
Objects.requireNonNull(entity);
mWindowProcessController.addOrUpdateBackgroundStartPrivileges(entity,
backgroundStartPrivileges);
+ setBackgroundStartPrivileges(entity, backgroundStartPrivileges);
}
void removeBackgroundStartPrivileges(Binder entity) {
Objects.requireNonNull(entity);
mWindowProcessController.removeBackgroundStartPrivileges(entity);
+ setBackgroundStartPrivileges(entity, null);
+ }
+
+ @NonNull
+ BackgroundStartPrivileges getBackgroundStartPrivileges() {
+ synchronized (mBackgroundStartPrivileges) {
+ if (mBackgroundStartPrivilegesMerged == null) {
+ // Lazily generate the merged version when it's actually needed.
+ mBackgroundStartPrivilegesMerged = BackgroundStartPrivileges.NONE;
+ for (int i = mBackgroundStartPrivileges.size() - 1; i >= 0; --i) {
+ mBackgroundStartPrivilegesMerged =
+ mBackgroundStartPrivilegesMerged.merge(
+ mBackgroundStartPrivileges.valueAt(i));
+ }
+ }
+ return mBackgroundStartPrivilegesMerged;
+ }
+ }
+
+ private void setBackgroundStartPrivileges(@NonNull Binder entity,
+ @Nullable BackgroundStartPrivileges backgroundStartPrivileges) {
+ synchronized (mBackgroundStartPrivileges) {
+ final boolean changed;
+ if (backgroundStartPrivileges == null) {
+ changed = mBackgroundStartPrivileges.remove(entity) != null;
+ } else {
+ final BackgroundStartPrivileges oldBsp =
+ mBackgroundStartPrivileges.put(entity, backgroundStartPrivileges);
+ // BackgroundStartPrivileges tries to reuse the same object and avoid creating
+ // additional objects. For now, we just compare the reference to see if something
+ // has changed.
+ // TODO: actually compare the individual values to see if there's a change
+ changed = backgroundStartPrivileges != oldBsp;
+ }
+ if (changed) {
+ mBackgroundStartPrivilegesMerged = null;
+ }
+ }
}
@Override
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/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index c0c286b..3c9af13 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -450,7 +450,7 @@
// so -2 is used instead
private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
- private static final float NITS_INVALID = -1;
+ static final float NITS_INVALID = -1;
// Length of the ambient light horizon used to calculate the long term estimate of ambient
// light.
@@ -840,7 +840,7 @@
/**
* Calculates the nits value for the specified backlight value if a mapping exists.
*
- * @return The mapped nits or 0 if no mapping exits.
+ * @return The mapped nits or {@link #NITS_INVALID} if no mapping exits.
*/
public float getNitsFromBacklight(float backlight) {
if (mBacklightToNitsSpline == null) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index b7b7031..213ee64 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -226,6 +226,16 @@
public static final int DIFF_COLOR_MODE = 1 << 2;
/**
+ * Diff result: The hdr/sdr ratio differs
+ */
+ public static final int DIFF_HDR_SDR_RATIO = 1 << 3;
+
+ /**
+ * Diff result: Catch-all for "everything changed"
+ */
+ public static final int DIFF_EVERYTHING = 0XFFFFFFFF;
+
+ /**
* Gets the name of the display device, which may be derived from EDID or
* other sources. The name may be localized and displayed to the user.
*/
@@ -414,6 +424,9 @@
public float brightnessMaximum;
public float brightnessDefault;
+ // NaN means unsupported
+ public float hdrSdrRatio = Float.NaN;
+
/**
* Install orientation of display panel relative to its natural orientation.
*/
@@ -449,6 +462,9 @@
if (colorMode != other.colorMode) {
diff |= DIFF_COLOR_MODE;
}
+ if (!BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)) {
+ diff |= DIFF_HDR_SDR_RATIO;
+ }
if (!Objects.equals(name, other.name)
|| !Objects.equals(uniqueId, other.uniqueId)
|| width != other.width
@@ -527,6 +543,7 @@
brightnessMinimum = other.brightnessMinimum;
brightnessMaximum = other.brightnessMaximum;
brightnessDefault = other.brightnessDefault;
+ hdrSdrRatio = other.hdrSdrRatio;
roundedCorners = other.roundedCorners;
installOrientation = other.installOrientation;
displayShape = other.displayShape;
@@ -575,6 +592,7 @@
sb.append(", brightnessMinimum ").append(brightnessMinimum);
sb.append(", brightnessMaximum ").append(brightnessMaximum);
sb.append(", brightnessDefault ").append(brightnessDefault);
+ sb.append(", hdrSdrRatio ").append(hdrSdrRatio);
if (roundedCorners != null) {
sb.append(", roundedCorners ").append(roundedCorners);
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index 33a63a9..ea52a3d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -42,7 +42,6 @@
private static final Boolean DEBUG = false;
public static final int DISPLAY_DEVICE_EVENT_ADDED = 1;
- public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2;
public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3;
/**
@@ -83,15 +82,15 @@
Trace.beginAsyncSection(tag, 0);
}
switch (event) {
- case DISPLAY_DEVICE_EVENT_ADDED:
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
handleDisplayDeviceAdded(device);
break;
- case DISPLAY_DEVICE_EVENT_CHANGED:
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
handleDisplayDeviceChanged(device);
break;
- case DISPLAY_DEVICE_EVENT_REMOVED:
+ case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
handleDisplayDeviceRemoved(device);
break;
}
@@ -174,7 +173,7 @@
if (diff == DisplayDeviceInfo.DIFF_STATE) {
Slog.i(TAG, "Display device changed state: \"" + info.name
+ "\", " + Display.stateToString(info.state));
- } else if (diff != 0) {
+ } else if (diff != DisplayDeviceInfo.DIFF_HDR_SDR_RATIO) {
Slog.i(TAG, "Display device changed: " + info);
}
@@ -188,7 +187,7 @@
device.mDebugLastLoggedDeviceInfo = info;
device.applyPendingDisplayDeviceInfoChangesLocked();
- sendEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
+ sendChangedEventLocked(device, diff);
if (DEBUG) {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -216,12 +215,22 @@
}
}
+ @GuardedBy("mSyncRoot")
+ private void sendChangedEventLocked(DisplayDevice device, int diff) {
+ final int size = mListeners.size();
+ for (int i = 0; i < size; i++) {
+ mListeners.get(i).onDisplayDeviceChangedLocked(device, diff);
+ }
+ }
+
/**
* Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}.
*/
public interface Listener {
void onDisplayDeviceEventLocked(DisplayDevice device, int event);
+ void onDisplayDeviceChangedLocked(DisplayDevice device, int diff);
+
// TODO: multi-display - Try to remove the need for requestTraversal...it feels like
// a shoe-horned method for a shoe-horned feature.
void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e200d12..9f1007d 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.
@@ -1745,6 +1747,10 @@
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
}
+ private void handleLogicalDisplayHdrSdrRatioChangedLocked(@NonNull LogicalDisplay display) {
+ sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED);
+ }
+
private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
.mDisplayDeviceConfig);
@@ -2025,12 +2031,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 +2056,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 +2208,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 +2253,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 +2824,10 @@
int[] getSupportedHdrOutputTypes() {
return DisplayControl.getSupportedHdrOutputTypes();
}
+
+ boolean getHdrOutputConversionSupport() {
+ return DisplayControl.getHdrOutputConversionSupport();
+ }
}
@VisibleForTesting
@@ -2983,6 +3028,10 @@
case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION:
handleLogicalDisplayDeviceStateTransitionLocked(display);
break;
+
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED:
+ handleLogicalDisplayHdrSdrRatioChangedLocked(display);
+ break;
}
}
@@ -3052,6 +3101,8 @@
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0;
case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
+ case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
+ return (mask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0;
default:
// This should never happen.
Slog.e(TAG, "Unknown display event " + event);
@@ -3757,6 +3808,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 +4091,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/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index be5980b..8f52c97 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -204,6 +204,7 @@
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ private float mCurrentHdrSdrRatio = Float.NaN;
private int mDefaultModeId = INVALID_MODE_ID;
private int mSystemPreferredModeId = INVALID_MODE_ID;
private int mDefaultModeGroup;
@@ -729,6 +730,7 @@
mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault();
+ mInfo.hdrSdrRatio = mCurrentHdrSdrRatio;
}
return mInfo;
}
@@ -840,12 +842,10 @@
private void setCommittedState(int state) {
// After the display state is set, let's update the committed state.
- getHandler().post(() -> {
- synchronized (getSyncRoot()) {
- mCommittedState = state;
- updateDeviceInfoLocked();
- }
- });
+ synchronized (getSyncRoot()) {
+ mCommittedState = state;
+ updateDeviceInfoLocked();
+ }
}
private void setDisplayBrightness(float brightnessState,
@@ -881,6 +881,9 @@
"SdrScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(
sdrBrightnessState));
+
+ handleHdrSdrNitsChanged(nits, sdrNits);
+
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -897,6 +900,23 @@
private float backlightToNits(float backlight) {
return getDisplayDeviceConfig().getNitsFromBacklight(backlight);
}
+
+ void handleHdrSdrNitsChanged(float displayNits, float sdrNits) {
+ final float newHdrSdrRatio;
+ if (displayNits != DisplayDeviceConfig.NITS_INVALID
+ && sdrNits != DisplayDeviceConfig.NITS_INVALID) {
+ newHdrSdrRatio = displayNits / sdrNits;
+ } else {
+ newHdrSdrRatio = Float.NaN;
+ }
+ if (!BrightnessSynchronizer.floatEquals(
+ mCurrentHdrSdrRatio, newHdrSdrRatio)) {
+ synchronized (getSyncRoot()) {
+ mCurrentHdrSdrRatio = newHdrSdrRatio;
+ updateDeviceInfoLocked();
+ }
+ }
+ }
};
}
return null;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 667c8c8..2104ee3 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -454,6 +454,7 @@
mBaseDisplayInfo.brightnessMinimum = deviceInfo.brightnessMinimum;
mBaseDisplayInfo.brightnessMaximum = deviceInfo.brightnessMaximum;
mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
+ mBaseDisplayInfo.hdrSdrRatio = deviceInfo.hdrSdrRatio;
mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index b48ba65..80e76b6 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -71,6 +71,7 @@
public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6;
+ public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7;
public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
@@ -226,14 +227,6 @@
handleDisplayDeviceAddedLocked(device);
break;
- case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
- if (DEBUG) {
- Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
- }
- finishStateTransitionLocked(false /*force*/);
- updateLogicalDisplaysLocked();
- break;
-
case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
if (DEBUG) {
Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
@@ -245,6 +238,15 @@
}
@Override
+ public void onDisplayDeviceChangedLocked(DisplayDevice device, int diff) {
+ if (DEBUG) {
+ Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
+ }
+ finishStateTransitionLocked(false /*force*/);
+ updateLogicalDisplaysLocked(diff);
+ }
+
+ @Override
public void onTraversalRequested() {
mListener.onTraversalRequested();
}
@@ -655,13 +657,20 @@
}
}
+ private void updateLogicalDisplaysLocked() {
+ updateLogicalDisplaysLocked(DisplayDeviceInfo.DIFF_EVERYTHING);
+ }
+
/**
* Updates the rest of the display system once all the changes are applied for display
* devices and logical displays. The includes releasing invalid/empty LogicalDisplays,
* creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the
* relevant changes.
+ *
+ * @param diff The DisplayDeviceInfo.DIFF_* of what actually changed to enable finer-grained
+ * display update listeners
*/
- private void updateLogicalDisplaysLocked() {
+ private void updateLogicalDisplaysLocked(int diff) {
// Go through all the displays and figure out if they need to be updated.
// Loops in reverse so that displays can be removed during the loop without affecting the
// rest of the loop.
@@ -715,7 +724,13 @@
} else if (!mTempDisplayInfo.equals(newDisplayInfo)) {
// FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
assignDisplayGroupLocked(display);
- mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+ // If only the hdr/sdr ratio changed, then send just the event for that case
+ if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) {
+ mLogicalDisplaysToUpdate.put(displayId,
+ LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
+ } else {
+ mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+ }
// The display is involved in a display layout transition
} else if (updateState == UPDATE_STATE_TRANSITION) {
@@ -774,6 +789,7 @@
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
+ sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED);
sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED);
@@ -1125,6 +1141,8 @@
return "swapped";
case LOGICAL_DISPLAY_EVENT_REMOVED:
return "removed";
+ case LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED:
+ return "hdr_sdr_ratio_changed";
}
return null;
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 172aa20..b2b22a0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -50,6 +50,7 @@
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.InputSensorInfo;
+import android.hardware.input.InputSettings;
import android.hardware.input.KeyboardLayout;
import android.hardware.input.TouchCalibration;
import android.hardware.lights.Light;
@@ -1309,7 +1310,7 @@
throw new SecurityException("Requires SET_POINTER_SPEED permission");
}
- if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
+ if (speed < InputSettings.MIN_POINTER_SPEED || speed > InputSettings.MAX_POINTER_SPEED) {
throw new IllegalArgumentException("speed out of range");
}
@@ -1317,8 +1318,8 @@
}
private void setPointerSpeedUnchecked(int speed) {
- speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
- InputManager.MAX_POINTER_SPEED);
+ speed = Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
+ InputSettings.MAX_POINTER_SPEED);
mNative.setPointerSpeed(speed);
}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index a113d01..5b21669 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -21,7 +21,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
-import android.hardware.input.InputManager;
+import android.hardware.input.InputSettings;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
@@ -32,7 +32,6 @@
import android.view.ViewConfiguration;
import java.util.Map;
-import java.util.Objects;
import java.util.function.Consumer;
/** Observes settings changes and propagates them to the native side. */
@@ -111,9 +110,9 @@
private int getPointerSpeedValue(String settingName) {
int speed = Settings.System.getIntForUser(mContext.getContentResolver(),
- settingName, InputManager.DEFAULT_POINTER_SPEED, UserHandle.USER_CURRENT);
- return Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
- InputManager.MAX_POINTER_SPEED);
+ settingName, InputSettings.DEFAULT_POINTER_SPEED, UserHandle.USER_CURRENT);
+ return Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
+ InputSettings.MAX_POINTER_SPEED);
}
private void updateMousePointerSpeed() {
@@ -170,8 +169,7 @@
}
private void updateMaximumObscuringOpacityForTouch() {
- InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
- final float opacity = im.getMaximumObscuringOpacityForTouch();
+ final float opacity = InputSettings.getMaximumObscuringOpacityForTouch(mContext);
if (opacity < 0 || opacity > 1) {
Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
+ ", it should be >= 0 and <= 1, rejecting update.");
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/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3799193..84ea077 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -320,12 +320,26 @@
MOBILE_NETWORK_SETTINGS);
}
+ /** Call intent with tel scheme */
+ private static final DefaultCrossProfileIntentFilter CALL =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_CALL)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addDataScheme("tel")
+ .build();
+
/**
* Returns default telephony related intent filters for managed profile.
*/
public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileTelephonyFilters() {
return Arrays.asList(
DIAL_DATA,
+ DIAL_MIME,
+ DIAL_RAW,
+ CALL,
SMS_MMS);
}
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7f1679a..449801d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3501,8 +3501,8 @@
}
@Override
- public void onKeyguardOccludedChangedLw(boolean occluded) {
- if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+ public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
+ if (mKeyguardDelegate != null && waitAppTransition) {
mPendingKeyguardOccluded = occluded;
mKeyguardOccludedChanged = true;
} else {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ca5fa5f..3c4dbf2 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -164,9 +164,10 @@
/**
* Called when the Keyguard occluded state changed.
+ *
* @param occluded Whether Keyguard is currently occluded or not.
*/
- void onKeyguardOccludedChangedLw(boolean occluded);
+ void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition);
/**
* @param notify {@code true} if the status change should be immediately notified via
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/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 5fd70a8..fc659c5 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -104,10 +104,10 @@
}
/**
- * Returns {@code true} if location time zone detection should run all the time on supported
- * devices, even when the user has not enabled it explicitly in settings. Enabled for internal
- * testing only. See {@link #isGeoDetectionExecutionEnabled()} and {@link #getDetectionMode()}
- * for details.
+ * Returns {@code true} if location time zone detection should run when auto time zone detection
+ * is enabled on supported devices, even when the user has not enabled the algorithm explicitly
+ * in settings. Enabled for internal testing only. See {@link #isGeoDetectionExecutionEnabled()}
+ * and {@link #getDetectionMode()} for details.
*/
boolean getGeoDetectionRunInBackgroundEnabledSetting() {
return mGeoDetectionRunInBackgroundEnabled;
@@ -219,6 +219,7 @@
private boolean getGeoDetectionRunInBackgroundEnabledBehavior() {
return isGeoDetectionSupported()
&& getLocationEnabledSetting()
+ && getAutoDetectionEnabledSetting()
&& getGeoDetectionRunInBackgroundEnabledSetting();
}
@@ -433,9 +434,9 @@
}
/**
- * Sets whether location time zone detection should run all the time on supported devices,
- * even when the user has not enabled it explicitly in settings. Enabled for internal
- * testing only.
+ * Sets whether location time zone detection should run when auto time zone detection is
+ * enabled on supported devices, even when the user has not enabled the algorithm explicitly
+ * in settings. Enabled for internal testing only.
*/
public Builder setGeoDetectionRunInBackgroundEnabled(boolean enabled) {
mGeoDetectionRunInBackgroundEnabled = enabled;
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/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index e9badef..32b3ccf 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -401,8 +401,10 @@
return;
}
- mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY));
- if (isKeyguardLocked(displayId)) {
+ final boolean waitAppTransition = isKeyguardLocked(displayId);
+ mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY),
+ waitAppTransition);
+ if (waitAppTransition) {
mService.deferWindowLayout();
try {
mRootWindowContainer.getDefaultDisplay()
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 43dbcc8..216544a 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1881,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
@@ -1888,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.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a63f9a3..ae7dc1e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -193,6 +193,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
+import android.hardware.input.InputSettings;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -744,7 +745,7 @@
private final DisplayHashController mDisplayHashController;
volatile float mMaximumObscuringOpacityForTouch =
- InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+ InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
@VisibleForTesting
final WindowContextListenerController mWindowContextListenerController =
@@ -886,11 +887,11 @@
ContentResolver resolver = mContext.getContentResolver();
mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
- InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
+ InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
if (mMaximumObscuringOpacityForTouch < 0.0f
|| mMaximumObscuringOpacityForTouch > 1.0f) {
mMaximumObscuringOpacityForTouch =
- InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+ InputSettings.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
}
}
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/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 8f16737..5013fb0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -33,6 +33,7 @@
import android.app.admin.PolicyUpdatesReceiver;
import android.app.admin.PolicyValue;
import android.app.admin.TargetUser;
+import android.app.admin.UserRestrictionPolicyKey;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -614,6 +615,47 @@
}
}
+ /**
+ * Returns all user restriction policies set by the given admin.
+ *
+ * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
+ * the admin
+ */
+ @NonNull
+ Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdmin(
+ @NonNull EnforcingAdmin admin,
+ int userId) {
+ Objects.requireNonNull(admin);
+ synchronized (mLock) {
+ if (userId == UserHandle.USER_ALL) {
+ return getUserRestrictionPolicyKeysForAdminLocked(mGlobalPolicies, admin);
+ }
+ if (!mLocalPolicies.contains(userId)) {
+ return Set.of();
+ }
+ return getUserRestrictionPolicyKeysForAdminLocked(mLocalPolicies.get(userId), admin);
+ }
+ }
+
+ private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked(
+ Map<PolicyKey, PolicyState<?>> policies,
+ EnforcingAdmin admin) {
+ Set<UserRestrictionPolicyKey> keys = new HashSet<>();
+ for (PolicyKey key : policies.keySet()) {
+ if (!policies.get(key).getPolicyDefinition().isUserRestrictionPolicy()) {
+ continue;
+ }
+ // User restriction policies are always boolean
+ PolicyValue<Boolean> value = (PolicyValue<Boolean>) policies.get(key)
+ .getPoliciesSetByAdmins().get(admin);
+ if (value == null || !value.getValue()) {
+ continue;
+ }
+ keys.add((UserRestrictionPolicyKey) key);
+ }
+ return keys;
+ }
+
private <V> boolean hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId) {
if (policyDefinition.isGlobalOnlyPolicy()) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cdcfaba..61ee0e7 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;
@@ -256,6 +264,7 @@
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.UnsafeStateException;
+import android.app.admin.UserRestrictionPolicyKey;
import android.app.admin.WifiSsidPolicy;
import android.app.backup.IBackupManager;
import android.app.compat.CompatChanges;
@@ -731,6 +740,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 +1169,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);
}
}
@@ -1334,7 +1352,7 @@
if (shouldMigrateToDevicePolicyEngine()) {
migratePoliciesToDevicePolicyEngine();
}
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.handlePackageChanged(packageName, userHandle);
}
// Persist updates if the removed package was an admin or delegate.
@@ -2001,7 +2019,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();
@@ -2026,7 +2045,7 @@
mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
mDeviceManagementResourcesProvider.load();
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.load();
}
@@ -2488,8 +2507,7 @@
if (profileOwner == null || !mUserManager.isManagedProfile(userId)) {
continue;
}
- maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner,
- UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+ maybeSetDefaultRestrictionsForAdminLocked(userId, profileOwner);
ensureUnknownSourcesRestrictionForProfileOwnerLocked(
userId, profileOwner, false /* newOwner */);
}
@@ -2504,9 +2522,20 @@
ActiveAdmin profileOwner, boolean newOwner) {
if (newOwner || mInjector.settingsSecureGetIntForUser(
Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
- profileOwner.ensureUserRestrictions().putBoolean(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
- saveUserRestrictionsLocked(userId);
+ if (isDevicePolicyEngineEnabled()) {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.getPolicyDefinitionForUserRestriction(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ profileOwner.info.getComponent(),
+ profileOwner.getUserHandle().getIdentifier()),
+ new BooleanPolicyValue(true),
+ userId);
+ } else {
+ profileOwner.ensureUserRestrictions().putBoolean(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+ saveUserRestrictionsLocked(userId);
+ }
mInjector.settingsSecurePutIntForUser(
Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
}
@@ -2515,11 +2544,28 @@
/**
* Apply default restrictions that haven't been applied to a given admin yet.
*/
- private void maybeSetDefaultRestrictionsForAdminLocked(
- int userId, ActiveAdmin admin, Set<String> defaultRestrictions) {
+ private void maybeSetDefaultRestrictionsForAdminLocked(int userId, ActiveAdmin admin) {
+ Set<String> defaultRestrictions =
+ UserRestrictionsUtils.getDefaultEnabledForManagedProfiles();
if (defaultRestrictions.equals(admin.defaultEnabledRestrictionsAlreadySet)) {
return; // The same set of default restrictions has been already applied.
}
+ if (isDevicePolicyEngineEnabled()) {
+ for (String restriction : defaultRestrictions) {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.getPolicyDefinitionForUserRestriction(restriction),
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin.info.getComponent(),
+ admin.getUserHandle().getIdentifier()),
+ new BooleanPolicyValue(true),
+ userId);
+ }
+ admin.defaultEnabledRestrictionsAlreadySet.addAll(defaultRestrictions);
+ Slogf.i(LOG_TAG, "Enabled the following restrictions by default: " +
+ defaultRestrictions);
+ return;
+ }
+
Slogf.i(LOG_TAG, "New user restrictions need to be set by default for user " + userId);
if (VERBOSE_LOG) {
@@ -3370,7 +3416,7 @@
updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs);
startOwnerService(userId, "start-user");
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.handleStartUser(userId);
}
}
@@ -3395,7 +3441,7 @@
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.handleUnlockUser(userId);
}
}
@@ -3407,7 +3453,7 @@
void handleStopUser(int userId) {
updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
mDeviceAdminServiceController.stopServicesForUser(userId, /* actionForLog= */ "stop-user");
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.handleStopUser(userId);
}
}
@@ -4168,6 +4214,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 +8539,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 +8600,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 +8625,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;
}
}
@@ -9292,8 +9386,7 @@
mInjector.binderWithCleanCallingIdentity(() -> {
if (mUserManager.isManagedProfile(userHandle)) {
- maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin,
- UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
+ maybeSetDefaultRestrictionsForAdminLocked(userHandle, admin);
ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin,
true /* newOwner */);
}
@@ -11437,7 +11530,7 @@
final int userId = user.id;
- if (isDevicePolicyEngineFlagEnabled()) {
+ if (isDevicePolicyEngineEnabled()) {
mDevicePolicyEngine.handleUserCreated(user);
}
@@ -12008,7 +12101,8 @@
}
@Override
- public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
+ public void setUserRestriction(
+ ComponentName who, String callerPackage, String key, boolean enabledFromThisOwner,
boolean parent) {
Objects.requireNonNull(who, "ComponentName is null");
@@ -12017,18 +12111,13 @@
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
-
if (parent) {
Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
} else {
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
}
-
int userId = caller.getUserId();
synchronized (getLockObject()) {
- final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(userId), parent);
-
if (isDefaultDeviceOwner(caller)) {
if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
throw new SecurityException("Device owner cannot set user restriction " + key);
@@ -12046,27 +12135,119 @@
boolean profileOwnerCanChangeOnItself = !parent
&& UserRestrictionsUtils.canProfileOwnerChange(
key, userId == getMainUserId());
- boolean orgOwnedProfileOwnerCanChangesGlobally = parent
+ boolean orgOwnedProfileOwnerCanChangeGlobally = parent
&& isProfileOwnerOfOrganizationOwnedDevice(caller)
&& UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
key);
- if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
+ if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
throw new SecurityException("Profile owner cannot set user restriction " + key);
}
}
- checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
-
- // Save the restriction to ActiveAdmin.
- final Bundle restrictions = activeAdmin.ensureUserRestrictions();
- if (enabledFromThisOwner) {
- restrictions.putBoolean(key, true);
- } else {
- restrictions.remove(key);
- }
- saveUserRestrictionsLocked(userId);
}
- final int eventId = enabledFromThisOwner
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
+
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ who, caller.getUserId());
+ PolicyDefinition<Boolean> policyDefinition =
+ PolicyDefinition.getPolicyDefinitionForUserRestriction(key);
+ if (enabledFromThisOwner) {
+ mDevicePolicyEngine.setLocalPolicy(
+ policyDefinition,
+ admin,
+ new BooleanPolicyValue(true),
+ parent ? getProfileParentId(userId) : userId);
+ } else {
+ // Remove any local and global policy that was set by the admin
+ if (!policyDefinition.isLocalOnlyPolicy()) {
+ mDevicePolicyEngine.removeGlobalPolicy(
+ policyDefinition,
+ admin);
+ }
+ if (!policyDefinition.isGlobalOnlyPolicy()) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ policyDefinition,
+ admin,
+ userId);
+
+ int parentUserId = getProfileParentId(userId);
+ if (parentUserId != userId) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ policyDefinition,
+ admin,
+ parentUserId);
+ }
+ }
+ }
+ } else {
+ synchronized (getLockObject()) {
+ final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+ getProfileOwnerOrDeviceOwnerLocked(userId), parent);
+ // Save the restriction to ActiveAdmin.
+ final Bundle restrictions = activeAdmin.ensureUserRestrictions();
+ if (enabledFromThisOwner) {
+ restrictions.putBoolean(key, true);
+ } else {
+ restrictions.remove(key);
+ }
+ saveUserRestrictionsLocked(userId);
+ }
+ }
+ logUserRestrictionCall(key, enabledFromThisOwner, parent, caller);
+ }
+
+ @Override
+ public void setUserRestrictionGlobally(String callerPackage, String key) {
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ // TODO: Replace with new permission checks, for now copying this over from
+ // setUserRestriction
+ if (!UserRestrictionsUtils.isValidRestriction(key)) {
+ return;
+ }
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+
+ int userHandle = caller.getUserId();
+ if (isDefaultDeviceOwner(caller)) {
+ if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
+ throw new SecurityException("Device owner cannot set user restriction " + key);
+ }
+ } else if (isFinancedDeviceOwner(caller)) {
+ if (!UserRestrictionsUtils.canFinancedDeviceOwnerChange(key)) {
+ throw new SecurityException("Cannot set user restriction " + key
+ + " when managing a financed device");
+ }
+ } else {
+ boolean profileOwnerCanChangeOnItself =
+ UserRestrictionsUtils.canProfileOwnerChange(key, userHandle == getMainUserId());
+ boolean orgOwnedProfileOwnerCanChangeGlobally =
+ isProfileOwnerOfOrganizationOwnedDevice(caller)
+ && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
+ key);
+
+ if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangeGlobally) {
+ throw new SecurityException("Profile owner cannot set user restriction " + key);
+ }
+ }
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
+
+ if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ throw new IllegalStateException("One or more admins are not targeting Android 14.");
+ }
+ EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ caller.getPackageName(), caller.getUserId());
+
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.getPolicyDefinitionForUserRestriction(key),
+ admin,
+ new BooleanPolicyValue(true));
+
+ logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller);
+ }
+
+ private void logUserRestrictionCall(
+ String key, boolean enabled, boolean parent, CallerIdentity caller) {
+ final int eventId = enabled
? DevicePolicyEnums.ADD_USER_RESTRICTION
: DevicePolicyEnums.REMOVE_USER_RESTRICTION;
DevicePolicyEventLogger
@@ -12075,14 +12256,18 @@
.setStrings(key, parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
.write();
if (SecurityLog.isLoggingEnabled()) {
- final int eventTag = enabledFromThisOwner
+ final int eventTag = enabled
? SecurityLog.TAG_USER_RESTRICTION_ADDED
: SecurityLog.TAG_USER_RESTRICTION_REMOVED;
- SecurityLog.writeEvent(eventTag, who.getPackageName(), userId, key);
+ SecurityLog.writeEvent(eventTag, caller.getPackageName(), caller.getUserId(), key);
}
}
private void saveUserRestrictionsLocked(int userId) {
+ if (isDevicePolicyEngineEnabled()) {
+ // User restrictions are handled in the policy engine
+ return;
+ }
saveSettingsLocked(userId);
pushUserRestrictions(userId);
sendChangedNotification(userId);
@@ -12144,7 +12329,7 @@
}
@Override
- public Bundle getUserRestrictions(ComponentName who, boolean parent) {
+ public Bundle getUserRestrictions(ComponentName who, String callerPackage, boolean parent) {
if (!mHasFeature) {
return null;
}
@@ -12156,14 +12341,59 @@
|| isProfileOwner(caller)
|| (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
- synchronized (getLockObject()) {
- final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
- return activeAdmin.userRestrictions;
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ return getUserRestrictionsFromPolicyEngine(
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(who, caller.getUserId()),
+ parent ? getProfileParentId(caller.getUserId()) : caller.getUserId());
+ } else {
+ synchronized (getLockObject()) {
+ final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+ getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ return activeAdmin.userRestrictions;
+ }
}
}
@Override
+ public Bundle getUserRestrictionsGlobally(String callerPackage) {
+ if (!mHasFeature) {
+ return null;
+ }
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ if (!useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ throw new IllegalStateException("One or more admins are not targeting Android 14.");
+ }
+ // TODO: Replace with new permission checks, for now copying this over from
+ // setUserRestriction
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isFinancedDeviceOwner(caller)
+ || isProfileOwner(caller));
+
+ return getUserRestrictionsFromPolicyEngine(
+ EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ caller.getPackageName(), caller.getUserId()),
+ UserHandle.USER_ALL);
+ }
+
+ /**
+ * Returns user restrictions set by the given admin for the provided {@code userId}.
+ *
+ * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
+ * the admin
+ */
+ private Bundle getUserRestrictionsFromPolicyEngine(EnforcingAdmin admin, int userId) {
+ Set<UserRestrictionPolicyKey> restrictionKeys =
+ mDevicePolicyEngine.getUserRestrictionPolicyKeysForAdmin(
+ admin,
+ userId);
+ Bundle restrictions = new Bundle();
+ for (UserRestrictionPolicyKey key : restrictionKeys) {
+ restrictions.putBoolean(key.getRestriction(), true);
+ }
+ return restrictions;
+ }
+
+ @Override
public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
boolean hidden, boolean parent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
@@ -13573,7 +13803,8 @@
+ " should be used instead.");
} else {
try {
- setUserRestriction(who, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ setUserRestriction(who, who.getPackageName(),
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
(Integer.parseInt(value) == 0) ? true : false, /* parent */ false);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
@@ -13630,7 +13861,8 @@
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_MASTER_VOLUME_MUTED);
synchronized (getLockObject()) {
- setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
+ setUserRestriction(who, who.getPackageName(), UserManager.DISALLOW_UNMUTE_DEVICE, on,
+ /* parent */ false);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_MASTER_VOLUME_MUTED)
.setAdmin(who)
@@ -13776,6 +14008,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 +15853,7 @@
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -15631,6 +15884,7 @@
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -18220,6 +18474,15 @@
}
});
}
+ String[] appOpExemptions = new String[exemptions.length];
+ for (int i = 0; i < exemptions.length; i++) {
+ appOpExemptions[i] = APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.get(exemptions[i]);
+ }
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_APPLICATION_EXEMPTIONS)
+ .setAdmin(caller.getPackageName())
+ .setStrings(packageName, appOpExemptions)
+ .write();
}
@Override
@@ -18679,6 +18942,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 +19389,7 @@
}
setUserSetupComplete(userInfo.id);
- startUser(userInfo.id, callerPackage);
+ startProfileForSetup(userInfo.id, callerPackage);
maybeMigrateAccount(
userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
provisioningParams.isKeepingAccountOnMigration(), callerPackage);
@@ -19280,8 +19620,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 +19633,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 +19647,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 +20743,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 +20760,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 +20906,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 +20919,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() {
@@ -21126,10 +21469,14 @@
}
return true;
} else {
- return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
+ return isDevicePolicyEngineEnabled();
}
}
+ private boolean isDevicePolicyEngineEnabled() {
+ return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
+ }
+
private boolean isDevicePolicyEngineFlagEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_DEVICE_POLICY_MANAGER,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 10e972d..7ed148b 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(
@@ -92,6 +93,15 @@
activeAdmin);
}
+
+ static EnforcingAdmin createEnterpriseEnforcingAdmin(
+ @NonNull String packageName, int userId) {
+ Objects.requireNonNull(packageName);
+ return new EnforcingAdmin(
+ packageName, /* componentName= */ null, Set.of(DPC_AUTHORITY), userId,
+ /* activeAdmin= */ null);
+ }
+
static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId) {
Objects.requireNonNull(componentName);
return new EnforcingAdmin(
@@ -111,11 +121,27 @@
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) {
+ String packageName, @Nullable ComponentName componentName, Set<String> authorities,
+ int userId, @Nullable ActiveAdmin activeAdmin) {
Objects.requireNonNull(packageName);
- Objects.requireNonNull(componentName);
Objects.requireNonNull(authorities);
// Role authorities should not be using this constructor
@@ -127,7 +153,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 +163,7 @@
mComponentName = null;
// authorities will be loaded when needed
mAuthorities = null;
- mActiveAdmin = null;
+ mActiveAdmin = activeAdmin;
}
private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -244,10 +270,12 @@
@Override
public int hashCode() {
if (mIsRoleAuthority) {
- // TODO(b/256854977): should we add UserId?
- return Objects.hash(mPackageName);
+ return Objects.hash(mPackageName, mUserId);
} else {
- return Objects.hash(mComponentName, getAuthorities());
+ return Objects.hash(
+ mComponentName == null ? mPackageName : mComponentName,
+ mUserId,
+ getAuthorities());
}
}
@@ -256,8 +284,10 @@
serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_ROLE, mIsRoleAuthority);
serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, mUserId);
if (!mIsRoleAuthority) {
- serializer.attribute(
- /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
+ if (mComponentName != null) {
+ serializer.attribute(
+ /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
+ }
// Role authorities get recomputed on load so no need to save them.
serializer.attribute(
/* namespace= */ null,
@@ -274,10 +304,11 @@
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);
+ ComponentName componentName = className == null
+ ? null : new ComponentName(packageName, className);
Set<String> authorities = Set.of(authoritiesStr.split(ATTR_AUTHORITIES_SEPARATOR));
return new EnforcingAdmin(packageName, componentName, authorities, userId, null);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 9e0da26..a08c2054 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;
@@ -28,10 +29,12 @@
import android.app.admin.PackagePolicyKey;
import android.app.admin.PolicyKey;
import android.app.admin.PolicyValue;
+import android.app.admin.UserRestrictionPolicyKey;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.UserManager;
import com.android.internal.util.function.QuadFunction;
import com.android.modules.utils.TypedXmlPullParser;
@@ -40,6 +43,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -66,6 +70,11 @@
// global policy please add support.
private static final int POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3;
+ // Add this flag to any policy that is a user restriction, the reason for this is that there
+ // are some special APIs to handle user restriction policies and this is the way we can identify
+ // them.
+ private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
+
private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
@@ -73,7 +82,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 +95,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 +122,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 +141,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 +154,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 +175,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 +185,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 +202,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 +211,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 +233,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<>(),
@@ -233,19 +246,124 @@
(Long value, Context context, Integer userId, PolicyKey policyKey) -> true,
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,
- USER_CONTROLLED_DISABLED_PACKAGES,
- DevicePolicyManager.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
- );
+ private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
+ private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
+ static {
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
+ GENERIC_PERMISSION_GRANT);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+ USER_CONTROLLED_DISABLED_PACKAGES);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ GENERIC_PERSISTENT_PREFERRED_ACTIVITY);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
+ GENERIC_PACKAGE_UNINSTALL_BLOCKED);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
+ GENERIC_APPLICATION_RESTRICTIONS);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
+ RESET_PASSWORD_TOKEN);
+
+ // User Restriction Policies
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_WIFI, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_CHANGE_WIFI_STATE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_ADD_WIFI_CONFIG, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCALE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_APPS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNINSTALL_APPS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_LOCATION, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_AIRPLANE_MODE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BRIGHTNESS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AMBIENT_DISPLAY, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+ POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_USB_FILE_TRANSFER, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DEBUGGING_FEATURES, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_VPN, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCATION, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_CONFIG_TETHERING, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_NETWORK_RESET, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_APPS_CONTROL, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_MICROPHONE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADJUST_VOLUME, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_CALLS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SMS, /* flags= */ 0);
+ // TODO: check if its global only
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FUN, /* flags= */ 0);
+ // TODO: check if its global only
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CREATE_WINDOWS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, /* flags= */ 0);
+ // TODO: check if its global only
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_BEAM, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_WALLPAPER, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_WALLPAPER, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SAFE_BOOT, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RECORD_AUDIO, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RUN_IN_BACKGROUND, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, /* flags= */ 0);
+ // TODO: double check flags
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_CAPTURE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_SUGGESTIONS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_USER_SWITCH, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_PRINTING, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, /* flags= */ 0);
+ // TODO: check if its global only
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, /* flags= */ 0);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+ USER_RESTRICTION_FLAGS.put(
+ UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY);
+
+ for (String key : USER_RESTRICTION_FLAGS.keySet()) {
+ createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
+ }
+ }
private final PolicyKey mPolicyKey;
private final ResolutionMechanism<V> mResolutionMechanism;
@@ -260,6 +378,17 @@
mPolicyEnforcerCallback, mPolicySerializer);
}
+ static PolicyDefinition<Boolean> getPolicyDefinitionForUserRestriction(
+ @UserManager.UserRestrictionKey String restriction) {
+ String key = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
+
+ if (!POLICY_DEFINITIONS.containsKey(key)) {
+ throw new IllegalArgumentException("Unsupported user restriction " + restriction);
+ }
+ // All user restrictions are of type boolean
+ return (PolicyDefinition<Boolean>) POLICY_DEFINITIONS.get(key);
+ }
+
@NonNull
PolicyKey getPolicyKey() {
return mPolicyKey;
@@ -298,6 +427,10 @@
return (mPolicyFlags & POLICY_FLAG_NON_COEXISTABLE_POLICY) != 0;
}
+ boolean isUserRestrictionPolicy() {
+ return (mPolicyFlags & POLICY_FLAG_USER_RESTRICTION_POLICY) != 0;
+ }
+
@Nullable
PolicyValue<V> resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy) {
return mResolutionMechanism.resolve(adminsPolicy);
@@ -307,6 +440,21 @@
return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
}
+ private static void createAndAddUserRestrictionPolicyDefinition(
+ String restriction, int flags) {
+ String identifier = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
+ UserRestrictionPolicyKey key = new UserRestrictionPolicyKey(identifier, restriction);
+ flags |= POLICY_FLAG_USER_RESTRICTION_POLICY;
+ PolicyDefinition<Boolean> definition = new PolicyDefinition<>(
+ key,
+ TRUE_MORE_RESTRICTIVE,
+ flags,
+ PolicyEnforcerCallbacks::setUserRestriction,
+ new BooleanPolicySerializer());
+ POLICY_DEFINITIONS.put(key.getIdentifier(), definition);
+ }
+
+
/**
* Callers must ensure that {@code policyType} have implemented an appropriate
* {@link Object#equals} implementation.
@@ -353,7 +501,7 @@
// TODO: can we avoid casting?
PolicyKey policyKey = readPolicyKeyFromXml(parser);
PolicyDefinition<V> genericPolicyDefinition =
- (PolicyDefinition<V>) sPolicyDefinitions.get(policyKey.getIdentifier());
+ (PolicyDefinition<V>) POLICY_DEFINITIONS.get(policyKey.getIdentifier());
return genericPolicyDefinition.createPolicyDefinition(policyKey);
}
@@ -362,7 +510,7 @@
// TODO: can we avoid casting?
PolicyKey policyKey = PolicyKey.readGenericPolicyKeyFromXml(parser);
PolicyDefinition<PolicyValue<V>> genericPolicyDefinition =
- (PolicyDefinition<PolicyValue<V>>) sPolicyDefinitions.get(
+ (PolicyDefinition<PolicyValue<V>>) POLICY_DEFINITIONS.get(
policyKey.getIdentifier());
return genericPolicyDefinition.mPolicyKey.readFromXml(parser);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 4ae7ca6..daa8a26 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -25,6 +25,7 @@
import android.app.admin.PackagePermissionPolicyKey;
import android.app.admin.PackagePolicyKey;
import android.app.admin.PolicyKey;
+import android.app.admin.UserRestrictionPolicyKey;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
@@ -40,6 +41,7 @@
import android.util.Slog;
import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
import java.util.Collections;
@@ -202,4 +204,22 @@
return true;
}));
}
+
+ static boolean setUserRestriction(
+ @Nullable Boolean enabled, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
+ return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
+ if (!(policyKey instanceof UserRestrictionPolicyKey)) {
+ throw new IllegalArgumentException("policyKey is not of type "
+ + "UserRestrictionPolicyKey");
+ }
+ UserRestrictionPolicyKey parsedKey =
+ (UserRestrictionPolicyKey) policyKey;
+ // TODO: call into new UserManager API when merged
+ UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
+// userManager.setUserRestriction(
+// userId, parsedKey.getRestriction(), enabled != null && enabled);
+ return true;
+ }));
+ }
}
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/searchui/java/com/android/server/searchui/SearchUiManagerService.java b/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
index 29ad537..c259701 100644
--- a/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
+++ b/services/searchui/java/com/android/server/searchui/SearchUiManagerService.java
@@ -140,12 +140,6 @@
}
@Override
- public void requestEmptyQueryResultUpdate(@NonNull SearchSessionId sessionId) {
- runForUserLocked("requestEmptyQueryResultUpdate", sessionId,
- (service) -> service.requestEmptyQueryResultUpdateLocked(sessionId));
- }
-
- @Override
public void destroySearchSession(@NonNull SearchSessionId sessionId) {
runForUserLocked("destroySearchSession", sessionId,
(service) -> service.onDestroyLocked(sessionId));
diff --git a/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java b/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
index 0d70fff..dc150cf 100644
--- a/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
+++ b/services/searchui/java/com/android/server/searchui/SearchUiPerUserService.java
@@ -181,16 +181,6 @@
}
/**
- * Requests a new set of search targets for empty query result used for zero state.
- */
- @GuardedBy("mLock")
- public void requestEmptyQueryResultUpdateLocked(@NonNull SearchSessionId sessionId) {
- final SearchSessionInfo sessionInfo = mSessionInfos.get(sessionId);
- if (sessionInfo == null) return;
- resolveService(sessionId, s->s.onRequestEmptyQueryResultUpdate(sessionId));
- }
-
- /**
* Notifies the service of the end of an existing search session.
*/
@GuardedBy("mLock")
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/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 4524759..95a5884 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -69,6 +69,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
@SmallTest
@@ -692,7 +694,10 @@
// Verify that committed triggered a new change event and is set correctly.
verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
- assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+ // We expect at least 1 update for the state change, but
+ // could get a second update for the initial brightness change if a nits mapping
+ // is available
+ assertThat(mListener.changedDisplays.size()).isAnyOf(1, 2);
assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isEqualTo(
Display.STATE_OFF);
@@ -964,6 +969,43 @@
.isTrue();
}
+ @Test
+ public void testHdrSdrRatio_notifiesOnChange() throws Exception {
+ FakeDisplay display = new FakeDisplay(PORT_A);
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+
+ // Turn on / initialize
+ Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 0,
+ 0);
+ changeStateRunnable.run();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ mListener.changedDisplays.clear();
+
+ assertEquals(1.0f, displayDevice.getDisplayDeviceInfoLocked().hdrSdrRatio, 0.001f);
+
+ // HDR time!
+ Runnable goHdrRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_ON, 1f,
+ 0);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ // Display state didn't change, no listeners should have happened
+ assertThat(mListener.changedDisplays.size()).isEqualTo(0);
+
+ // Execute hdr change.
+ goHdrRunnable.run();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ // Display state didn't change, expect to only get the HDR/SDR ratio change notification
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+ final float expectedRatio = DISPLAY_RANGE_NITS[1] / DISPLAY_RANGE_NITS[0];
+ assertEquals(expectedRatio, displayDevice.getDisplayDeviceInfoLocked().hdrSdrRatio,
+ 0.001f);
+ }
+
private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort,
float expectedXdpi,
float expectedYDpi,
@@ -1107,15 +1149,9 @@
private static void waitForHandlerToComplete(Handler handler, long waitTimeMs)
throws InterruptedException {
- final Object lock = new Object();
- synchronized (lock) {
- handler.post(() -> {
- synchronized (lock) {
- lock.notify();
- }
- });
- lock.wait(waitTimeMs);
- }
+ final CountDownLatch fence = new CountDownLatch(1);
+ handler.post(fence::countDown);
+ assertTrue(fence.await(waitTimeMs, TimeUnit.MILLISECONDS));
}
private class HotplugTransmitter {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
index 3750aa0..2fbbf0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -49,6 +49,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
+import android.app.BackgroundStartPrivileges;
import android.app.IActivityManager;
import android.app.job.JobInfo;
import android.content.ComponentName;
@@ -63,6 +64,7 @@
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.SparseIntArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -178,6 +180,8 @@
mGracePeriodObserver = mock(GracePeriodObserver.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ doReturn(BackgroundStartPrivileges.NONE)
+ .when(mActivityManagerInternal).getBackgroundStartPrivileges(anyInt());
mDefaultUserId = mNextUserId;
createCurrentUser(true);
mNextUserId = 10;
@@ -601,34 +605,75 @@
@Test
public void testHasImmediacyPrivilege() {
- JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, 0);
+ final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE;
+ JobStatus job = createJob(uid, 0);
spyOn(job);
- assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ doReturn(BackgroundStartPrivileges.NONE)
+ .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
doReturn(false).when(job).shouldTreatAsExpeditedJob();
doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
- assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
doReturn(true).when(job).shouldTreatAsExpeditedJob();
doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
- assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
doReturn(false).when(job).shouldTreatAsExpeditedJob();
doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
- assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
doReturn(false).when(job).shouldTreatAsExpeditedJob();
doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
- assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
doReturn(true).when(job).shouldTreatAsExpeditedJob();
doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
job.lastEvaluatedBias = JobInfo.BIAS_TOP_APP;
- assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job));
+ assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job,
+ new SparseIntArray()));
+
+ doReturn(BackgroundStartPrivileges.ALLOW_FGS)
+ .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+ doReturn(false).when(job).shouldTreatAsExpeditedJob();
+ doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+ doReturn(true).when(job).shouldTreatAsExpeditedJob();
+ doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+ doReturn(false).when(job).shouldTreatAsExpeditedJob();
+ doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+ doReturn(BackgroundStartPrivileges.ALLOW_BAL)
+ .when(mActivityManagerInternal).getBackgroundStartPrivileges(uid);
+
+ doReturn(false).when(job).shouldTreatAsExpeditedJob();
+ doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+ doReturn(true).when(job).shouldTreatAsExpeditedJob();
+ doReturn(false).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertFalse(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
+
+ doReturn(false).when(job).shouldTreatAsExpeditedJob();
+ doReturn(true).when(job).shouldTreatAsUserInitiatedJob();
+ job.lastEvaluatedBias = JobInfo.BIAS_DEFAULT;
+ assertTrue(mJobConcurrencyManager.hasImmediacyPrivilegeLocked(job, new SparseIntArray()));
}
@Test
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/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index b5c5582..120ddf6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -49,6 +49,7 @@
import com.android.server.SystemService;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -156,6 +157,7 @@
@SmallTest
@Test
+ @Ignore("b/269249457")
public void testCompMigrationAffiliated() throws Exception {
prepareAdmin1AsDo();
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
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/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 0d6bb8a..566c6b0 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -570,7 +570,7 @@
.setAutoDetectionEnabledSetting(false)
.build();
assertFalse(config.getAutoDetectionEnabledBehavior());
- assertTrue(config.isGeoDetectionExecutionEnabled());
+ assertFalse(config.isGeoDetectionExecutionEnabled());
assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
}
}
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/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
index 7b1db95..aeb8ec8 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderControllerTest.java
@@ -24,6 +24,7 @@
import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_UNKNOWN;
import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_MANUAL;
+import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_TELEPHONY;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
@@ -1385,6 +1386,37 @@
}
/**
+ * A controller-state-only test to prove that "run in background" doesn't enable the
+ * location-based time zone detection algorithm to run when auto detection is disabled.
+ */
+ @Test
+ public void geoDetectionRunInBackground_obeysAutoDetectionDisabled() {
+ LocationTimeZoneProviderController controller = new LocationTimeZoneProviderController(
+ mTestThreadingDomain, mTestMetricsLogger, mTestPrimaryLocationTimeZoneProvider,
+ mTestSecondaryLocationTimeZoneProvider, false /* recordStateChanges */);
+
+ // A configuration where the user has auto detection disabled.
+ ConfigurationInternal autoTimeZoneDisabledConfig =
+ new ConfigurationInternal.Builder(USER1_CONFIG_GEO_DETECTION_DISABLED)
+ .setLocationEnabledSetting(true)
+ .setAutoDetectionEnabledSetting(false)
+ .setGeoDetectionEnabledSetting(true)
+ .setGeoDetectionRunInBackgroundEnabled(true)
+ .build();
+ assertEquals(DETECTION_MODE_MANUAL, autoTimeZoneDisabledConfig.getDetectionMode());
+ assertFalse(autoTimeZoneDisabledConfig.isGeoDetectionExecutionEnabled());
+
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controller, autoTimeZoneDisabledConfig);
+
+ // Initialize and check initial state.
+ controller.initialize(testEnvironment, mTestCallback);
+
+ assertControllerState(controller, STATE_STOPPED);
+ mTestMetricsLogger.assertStateChangesAndCommit(STATE_PROVIDERS_INITIALIZING, STATE_STOPPED);
+ }
+
+ /**
* A controller-state-only test to prove that "run in background" configuration behaves as
* intended. Provider states are well covered by other "enabled" tests.
*/
@@ -1398,7 +1430,7 @@
ConfigurationInternal runInBackgroundDisabledConfig =
new ConfigurationInternal.Builder(USER1_CONFIG_GEO_DETECTION_DISABLED)
.setLocationEnabledSetting(true)
- .setAutoDetectionEnabledSetting(false)
+ .setAutoDetectionEnabledSetting(true)
.setGeoDetectionEnabledSetting(false)
.setGeoDetectionRunInBackgroundEnabled(false)
.build();
@@ -1408,7 +1440,7 @@
new ConfigurationInternal.Builder(runInBackgroundDisabledConfig)
.setGeoDetectionRunInBackgroundEnabled(true)
.build();
- assertEquals(DETECTION_MODE_MANUAL, runInBackgroundEnabledConfig.getDetectionMode());
+ assertEquals(DETECTION_MODE_TELEPHONY, runInBackgroundEnabledConfig.getDetectionMode());
assertTrue(runInBackgroundEnabledConfig.isGeoDetectionExecutionEnabled());
TestEnvironment testEnvironment = new TestEnvironment(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 009b259..687696a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -203,6 +203,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -376,7 +377,7 @@
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
- TestFlagResolver mTestFlagResolver = new TestFlagResolver();
+ TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 6f2627a..a3977ba 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -64,6 +64,7 @@
import androidx.test.InstrumentationRegistry;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.server.LocalServices;
@@ -168,7 +169,7 @@
mock(ActivityManagerInternal.class),
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
- mock(NotificationChannelLogger.class), new TestFlagResolver());
+ mock(NotificationChannelLogger.class), new TestableFlagResolver());
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 3344bdb..1d0715a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -222,7 +222,7 @@
}
@Override
- public void onKeyguardOccludedChangedLw(boolean occluded) {
+ public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
}
public void setSafeMode(boolean safeMode) {
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/ISatelliteStateListener.aidl b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
index 0ce9c98..cc4c543 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
@@ -26,7 +26,8 @@
oneway interface ISatelliteStateListener {
void onSatelliteProvisionStateChanged(in boolean provisioned);
void onSatellitePositionUpdate(in PointingInfo pointingInfo);
- void onMessageTransferStateUpdate(in int state);
+ void onMessageTransferStateUpdate(in int state, in int sendPendingCount,
+ in int receivePendingCount, in int errorCode);
void onSatelliteModemStateChange(in int state);
void onPendingMessageCount(in int count);
void onSatelliteDatagrams(in SatelliteDatagram[] datagrams);
diff --git a/telephony/java/android/telephony/satellite/SatelliteCallback.java b/telephony/java/android/telephony/satellite/SatelliteCallback.java
index 5250562..7f24a2f 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCallback.java
@@ -20,7 +20,6 @@
import android.os.Binder;
import java.lang.ref.WeakReference;
-import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -70,7 +69,7 @@
}
/**
- * Interface for position update change listener.
+ * Interface for position update and message transfer state change listener.
*/
public interface SatellitePositionUpdateListener {
/**
@@ -84,9 +83,13 @@
* Called when satellite message transfer state changes.
*
* @param state The new message transfer state.
+ * @param sendPendingCount The number of messages that are currently being sent.
+ * @param receivePendingCount The number of messages that are currently being received.
+ * @param errorCode If message transfer failed, the reason for failure.
*/
void onMessageTransferStateUpdate(
- @SatelliteManager.SatelliteMessageTransferState int state);
+ @SatelliteManager.SatelliteMessageTransferState int state, int sendPendingCount,
+ int receivePendingCount, @SatelliteManager.SatelliteError int errorCode);
}
/**
@@ -95,13 +98,13 @@
public interface SatelliteStateListener {
/**
* Called when satellite state changes.
- * @param state - The new satellite state.
+ * @param state The new satellite state.
*/
void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state);
/**
* Called when there are pending messages to be received from satellite.
- * @param count - pending message count.
+ * @param count Pending message count.
*/
void onPendingMessageCount(int count);
}
@@ -112,7 +115,7 @@
public interface SatelliteDatagramListener {
/**
* Called when there are incoming datagrams to be received.
- * @param datagrams - datagrams to be received over satellite.
+ * @param datagrams Datagrams to be received over satellite.
*/
void onSatelliteDatagrams(SatelliteDatagram[] datagrams);
}
@@ -145,13 +148,15 @@
}
public void onMessageTransferStateUpdate(
- @SatelliteManager.SatelliteMessageTransferState int state) {
+ @SatelliteManager.SatelliteMessageTransferState int state, int sendPendingCount,
+ int receivePendingCount, @SatelliteManager.SatelliteError int errorCode) {
SatellitePositionUpdateListener listener =
(SatellitePositionUpdateListener) mSatelliteCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
- () -> listener.onMessageTransferStateUpdate(state)));
+ () -> listener.onMessageTransferStateUpdate(
+ state, sendPendingCount, receivePendingCount, errorCode)));
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
index c5ae4db..74f6f57 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCapabilities.java
@@ -33,8 +33,8 @@
private Set<Integer> mSupportedRadioTechnologies;
/**
- * Whether satellite mode is always on (this to indicate power impact of keeping it on is
- * very minimal).
+ * Whether satellite modem is always on.
+ * This indicates the power impact of keeping it on is very minimal.
*/
private boolean mIsAlwaysOn;
@@ -44,12 +44,7 @@
private boolean mNeedsPointingToSatellite;
/**
- * List of features supported by the Satellite modem.
- */
- private Set<Integer> mSupportedFeatures;
-
- /**
- * Whether UE needs a separate SIM profile to communicate with the Satellite network.
+ * Whether UE needs a separate SIM profile to communicate with the satellite network.
*/
private boolean mNeedsSeparateSimProfile;
@@ -57,12 +52,10 @@
* @hide
*/
public SatelliteCapabilities(Set<Integer> supportedRadioTechnologies, boolean isAlwaysOn,
- boolean needsPointingToSatellite, Set<Integer> supportedFeatures,
- boolean needsSeparateSimProfile) {
+ boolean needsPointingToSatellite, boolean needsSeparateSimProfile) {
mSupportedRadioTechnologies = supportedRadioTechnologies;
mIsAlwaysOn = isAlwaysOn;
mNeedsPointingToSatellite = needsPointingToSatellite;
- mSupportedFeatures = supportedFeatures;
mNeedsSeparateSimProfile = needsSeparateSimProfile;
}
@@ -88,35 +81,23 @@
out.writeBoolean(mIsAlwaysOn);
out.writeBoolean(mNeedsPointingToSatellite);
-
- if (mSupportedFeatures != null && !mSupportedFeatures.isEmpty()) {
- out.writeInt(mSupportedFeatures.size());
- for (int feature : mSupportedFeatures) {
- out.writeInt(feature);
- }
- } else {
- out.writeInt(0);
- }
-
out.writeBoolean(mNeedsSeparateSimProfile);
}
- public static final @android.annotation.NonNull Creator<SatelliteCapabilities> CREATOR =
- new Creator<SatelliteCapabilities>() {
- @Override
- public SatelliteCapabilities createFromParcel(Parcel in) {
- return new SatelliteCapabilities(in);
- }
+ @NonNull public static final Creator<SatelliteCapabilities> CREATOR = new Creator<>() {
+ @Override
+ public SatelliteCapabilities createFromParcel(Parcel in) {
+ return new SatelliteCapabilities(in);
+ }
- @Override
- public SatelliteCapabilities[] newArray(int size) {
- return new SatelliteCapabilities[size];
- }
- };
+ @Override
+ public SatelliteCapabilities[] newArray(int size) {
+ return new SatelliteCapabilities[size];
+ }
+ };
- @NonNull
@Override
- public String toString() {
+ @NonNull public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SupportedRadioTechnology:");
@@ -129,16 +110,6 @@
sb.append("none,");
}
- sb.append("SupportedFeatures:");
- if (mSupportedFeatures != null && !mSupportedFeatures.isEmpty()) {
- for (int feature : mSupportedFeatures) {
- sb.append(feature);
- sb.append(",");
- }
- } else {
- sb.append("none,");
- }
-
sb.append("isAlwaysOn:");
sb.append(mIsAlwaysOn);
sb.append(",");
@@ -152,26 +123,39 @@
return sb.toString();
}
- @NonNull
- public Set<Integer> getSupportedRadioTechnologies() {
+ /**
+ * @return The list of technologies supported by the satellite modem.
+ */
+ @NonNull public Set<Integer> getSupportedRadioTechnologies() {
return mSupportedRadioTechnologies;
}
+ /**
+ * Get whether the satellite modem is always on.
+ * This indicates the power impact of keeping it on is very minimal.
+ *
+ * @return {@code true} if the satellite modem is always on and {@code false} otherwise.
+ */
public boolean isAlwaysOn() {
return mIsAlwaysOn;
}
- /** Get function for mNeedsPointingToSatellite */
+ /**
+ * Get whether UE needs to point to a satellite to send and receive data.
+ *
+ * @return {@code true} if UE needs to pointing to a satellite to send and receive data and
+ * {@code false} otherwise.
+ */
public boolean needsPointingToSatellite() {
return mNeedsPointingToSatellite;
}
- @NonNull
- public Set<Integer> getSupportedFeatures() {
- return mSupportedFeatures;
- }
-
- /** Get function for mNeedsSeparateSimProfile */
+ /**
+ * Get whether UE needs a separate SIM profile to communicate with the satellite network.
+ *
+ * @return {@code true} if UE needs a separate SIM profile to comunicate with the satellite
+ * network and {@code false} otherwise.
+ */
public boolean needsSeparateSimProfile() {
return mNeedsSeparateSimProfile;
}
@@ -187,15 +171,6 @@
mIsAlwaysOn = in.readBoolean();
mNeedsPointingToSatellite = in.readBoolean();
-
- mSupportedFeatures = new HashSet<>();
- int numSupportedFeatures = in.readInt();
- if (numSupportedFeatures > 0) {
- for (int i = 0; i < numSupportedFeatures; i++) {
- mSupportedFeatures.add(in.readInt());
- }
- }
-
mNeedsSeparateSimProfile = in.readBoolean();
}
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 5f6218d..9ce4310 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -144,6 +144,21 @@
public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
/**
+ * Bundle key to get the response from
+ * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_COMMUNICATION_ALLOWED =
+ "satellite_communication_allowed";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestTimeForNextSatelliteVisibility(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_NEXT_VISIBILITY = "satellite_next_visibility";
+
+ /**
* The request was successfully processed.
*/
public static final int SATELLITE_ERROR_NONE = 0;
@@ -294,7 +309,7 @@
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "setSatelliteEnabled RemoteException: ", ex);
+ Rlog.e(TAG, "setSatelliteEnabled() RemoteException: ", ex);
ex.rethrowFromSystemServer();
}
}
@@ -460,33 +475,45 @@
}
/**
- * Message transfer is waiting to acquire.
+ * The default state indicating that message transfer is idle.
+ * This should be sent immediately after either
+ * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS} or
+ * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_FAILED}.
*/
- public static final int SATELLITE_MESSAGE_TRANSFER_STATE_WAITING_TO_ACQUIRE = 0;
+ public static final int SATELLITE_MESSAGE_TRANSFER_STATE_IDLE = 0;
/**
- * Message is being sent.
+ * A transition state indicating that a message is being sent.
*/
public static final int SATELLITE_MESSAGE_TRANSFER_STATE_SENDING = 1;
/**
- * Message is being received.
+ * A transition state indicating that a message is being received.
*/
public static final int SATELLITE_MESSAGE_TRANSFER_STATE_RECEIVING = 2;
/**
- * Message transfer is being retried.
+ * A transition state indicating that message transfer is being retried.
*/
public static final int SATELLITE_MESSAGE_TRANSFER_STATE_RETRYING = 3;
/**
- * Message transfer is complete.
+ * An end state indicating that message transfer completed successfully.
+ * After message transfer completes, {@link #SATELLITE_MESSAGE_TRANSFER_STATE_IDLE}
+ * must be sent before reporting any additional message transfer state changes.
*/
- public static final int SATELLITE_MESSAGE_TRANSFER_STATE_COMPLETE = 4;
+ public static final int SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS = 4;
+ /**
+ * An end state indicating that message transfer completed with a failure.
+ * After message transfer completes, {@link #SATELLITE_MESSAGE_TRANSFER_STATE_IDLE}
+ * must be sent before reporting any additional message transfer state changes.
+ */
+ public static final int SATELLITE_MESSAGE_TRANSFER_STATE_FAILED = 5;
/** @hide */
@IntDef(prefix = {"SATELLITE_MESSAGE_TRANSFER_STATE_"}, value = {
- SATELLITE_MESSAGE_TRANSFER_STATE_WAITING_TO_ACQUIRE,
+ SATELLITE_MESSAGE_TRANSFER_STATE_IDLE,
SATELLITE_MESSAGE_TRANSFER_STATE_SENDING,
SATELLITE_MESSAGE_TRANSFER_STATE_RECEIVING,
SATELLITE_MESSAGE_TRANSFER_STATE_RETRYING,
- SATELLITE_MESSAGE_TRANSFER_STATE_COMPLETE
+ SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS,
+ SATELLITE_MESSAGE_TRANSFER_STATE_FAILED
})
public @interface SatelliteMessageTransferState {}
@@ -534,6 +561,11 @@
* Modem should continue to report the pointing input as the device or satellite moves.
* Satellite position updates are started only on {@link #SATELLITE_ERROR_NONE}.
* All other results indicate that this operation failed.
+ * Once satellite position updates begin, message transfer state updates will be sent
+ * through {@link SatelliteCallback.SatellitePositionUpdateListener}.
+ * Modem should report any changes in message transfer state and indicate success or failure
+ * by reporting {@link #SATELLITE_MESSAGE_TRANSFER_STATE_SUCCESS} or
+ * {@link #SATELLITE_MESSAGE_TRANSFER_STATE_FAILED}.
*
* @param executor The executor on which the callback and error code listener will be called.
* @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
@@ -568,7 +600,7 @@
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("startSatellitePositionUpdates RemoteException: " + ex);
+ loge("startSatellitePositionUpdates() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
}
@@ -576,8 +608,8 @@
/**
* Stop receiving satellite position updates.
* This can be called by the pointing UI when the user stops pointing to the satellite.
- * Satellite position updates are stopped only on {@link #SATELLITE_ERROR_NONE}.
- * All other results indicate that this operation failed.
+ * Satellite position updates are stopped and the callback is unregistered only on
+ * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed.
*
* @param callback The callback that was passed to
* {@link #startSatellitePositionUpdates(Executor, Consumer, SatelliteCallback)}.
@@ -585,7 +617,6 @@
* @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
*
* @throws SecurityException if the caller doesn't have required permission.
- * @throws IllegalArgumentException if the callback is invalid.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@@ -613,7 +644,7 @@
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("stopSatellitePositionUpdates RemoteException: " + ex);
+ loge("stopSatellitePositionUpdates() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
}
@@ -671,7 +702,6 @@
}
}
-
/**
* Provision the device with a satellite provider.
* This is needed if the provider allows dynamic registration.
@@ -712,7 +742,7 @@
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("provisionSatelliteService RemoteException=" + ex);
+ loge("provisionSatelliteService() RemoteException=" + ex);
ex.rethrowFromSystemServer();
}
if (cancellationSignal != null) {
@@ -757,7 +787,7 @@
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("deprovisionSatelliteService RemoteException=" + ex);
+ loge("deprovisionSatelliteService() RemoteException=" + ex);
ex.rethrowFromSystemServer();
}
}
@@ -765,90 +795,72 @@
/**
* Register for the satellite provision state change.
*
- * @param executor The executor on which the callback and error code listener will be called.
- * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
- * @param callback The callback to handle the satellite provision state changed event. This
- * SatelliteCallback should implement the interface
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback to handle the satellite provision state changed event.
+ * This SatelliteCallback should implement the interface
* {@link SatelliteCallback.SatelliteProvisionStateListener}.
*
+ * @return The {@link SatelliteError} 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 registerForSatelliteProvisionStateChanged(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Integer> errorCodeListener, @NonNull SatelliteCallback callback) {
+ @SatelliteError public int registerForSatelliteProvisionStateChanged(
+ @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
- Objects.requireNonNull(errorCodeListener);
Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
callback.init(executor);
- IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
- @Override
- public void accept(int result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> errorCodeListener.accept(result)));
- }
- };
- telephony.registerForSatelliteProvisionStateChanged(
- mSubId, errorCallback, callback.getCallbackStub());
+ return telephony.registerForSatelliteProvisionStateChanged(
+ mSubId, callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("registerForSatelliteProvisionStateChanged RemoteException: " + ex);
+ loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
+ return SATELLITE_REQUEST_FAILED;
}
/**
* Unregister for the satellite provision state change.
*
- * @param callback The callback that was passed to
- * {@link #registerForSatelliteProvisionStateChanged(Executor, Consumer, SatelliteCallback)}.
- * @param executor The executor on which the error code listener will be called.
- * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
+ * @param callback The callback that was passed to {@link
+ * #registerForSatelliteProvisionStateChanged(Executor, SatelliteCallback)}.
+ *
+ * @return The {@link SatelliteError} 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 unregisterForSatelliteProvisionStateChanged(@NonNull SatelliteCallback callback,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Integer> errorCodeListener) {
+ @SatelliteError public int unregisterForSatelliteProvisionStateChanged(
+ @NonNull SatelliteCallback callback) {
Objects.requireNonNull(callback);
- Objects.requireNonNull(executor);
- Objects.requireNonNull(errorCodeListener);
if (callback.getCallbackStub() == null) {
loge("unregisterForSatelliteProvisionStateChanged: callbackStub is null");
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> errorCodeListener.accept(SATELLITE_INVALID_ARGUMENTS)));
- return;
+ return SATELLITE_INVALID_ARGUMENTS;
}
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
- @Override
- public void accept(int result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> errorCodeListener.accept(result)));
- }
- };
- telephony.unregisterForSatelliteProvisionStateChanged(mSubId, errorCallback,
+ return telephony.unregisterForSatelliteProvisionStateChanged(mSubId,
callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteProvisionStateChanged RemoteException: " + ex);
+ loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
+ return SATELLITE_REQUEST_FAILED;
}
/**
@@ -908,19 +920,19 @@
/**
* Register for listening to satellite modem state changes.
*
- * @param executor - The executor on which the callback will be called.
- * @param callback - The callback to handle the satellite state change event. This
- * SatelliteCallback should implement the interface
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback to handle the satellite state change event.
+ * This SatelliteCallback should implement the interface
* {@link SatelliteCallback.SatelliteStateListener}.
*
- * @return The error code of the request.
+ * @return The {@link SatelliteError} 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)
- @SatelliteError
- public int registerForSatelliteModemStateChange(@NonNull @CallbackExecutor Executor executor,
- @NonNull SatelliteCallback callback) {
+ @SatelliteError public int registerForSatelliteModemStateChange(
+ @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -943,10 +955,11 @@
/**
* Unregister to stop listening to satellite modem state changes.
*
- * @param callback - The callback that was passed to
- * {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}
+ * @param callback The callback that was passed to
+ * {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}.
*
- * @return The error code of the request.
+ * @return The {@link SatelliteError} result of the operation.
+ *
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@@ -978,19 +991,19 @@
/**
* Register to receive incoming datagrams over satellite.
*
- * @param datagramType - type of datagram
- * @param executor - The executor on which the callback will be called.
- * @param callback - The callback to handle incoming datagrams over satellite. This
- * SatelliteCallback should implement the interface
+ * @param datagramType Type of datagram.
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback to handle incoming datagrams over satellite.
+ * This SatelliteCallback should implement the interface
* {@link SatelliteCallback.SatelliteDatagramListener}.
*
- * @return The error code of the request.
+ * @return The {@link SatelliteError} 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)
- @SatelliteError
- public int registerForSatelliteDatagram(@DatagramType int datagramType,
+ @SatelliteError public int registerForSatelliteDatagram(@DatagramType int datagramType,
@NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -1014,16 +1027,16 @@
/**
* Unregister to stop receiving incoming datagrams over satellite.
*
- * @param callback - The callback that was passed to
- * {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}
+ * @param callback The callback that was passed to
+ * {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}.
*
- * @return The error code of the request.
+ * @return The {@link SatelliteError} 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)
- @SatelliteError
- public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
+ @SatelliteError public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
Objects.requireNonNull(callback);
if (callback.getCallbackStub() == null) {
@@ -1034,8 +1047,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.unregisterForSatelliteDatagram(mSubId,
- callback.getCallbackStub());
+ return telephony.unregisterForSatelliteDatagram(mSubId, callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -1054,8 +1066,7 @@
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError
- public int pollPendingSatelliteDatagrams() {
+ @SatelliteError public int pollPendingSatelliteDatagrams() {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
@@ -1070,6 +1081,158 @@
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 error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} 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> errorCodeListener) {
+ Objects.requireNonNull(datagram);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.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();
+ }
+ }
+
+ /**
+ * Request to get whether satellite communication is allowed for the current location.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return a {@code boolean} with value {@code true} if satellite
+ * communication is allowed for the current location and
+ * {@code false} otherwise.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
+ *
+ * @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 requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
+ boolean isSatelliteCommunicationAllowed =
+ resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isSatelliteCommunicationAllowed)));
+ } else {
+ loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId,
+ receiver);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: "
+ + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request to get the time after which the satellite will next be visible. This is an
+ * {@code int} representing the duration in seconds after which the satellite will be visible.
+ * This will return {@code 0} if the satellite is currently visible.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return the time after which the satellite will next be visible.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
+ *
+ * @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 requestTimeForNextSatelliteVisibility(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
+ int nextVisibilityDuration =
+ resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(nextVisibilityDuration)));
+ } else {
+ loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("requestTimeForNextSatelliteVisibility() 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..ec8dafb 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;
@@ -2770,7 +2771,7 @@
/**
* Request to get the maximum number of characters per text message on satellite.
*
- * @param subId The subId to get the maximum number of characters for.
+ * @param subId The subId of the subscription to get the maximum number of characters for.
* @param receiver Result receiver to get the error code of the request and the requested
* maximum number of characters per text message on satellite.
*/
@@ -2813,26 +2814,26 @@
/**
* Register for the satellite provision state change.
*
- * @param subId The subId of the subscription to register for provision state changes for.
- * @param errorCallback The callback to get the error code of the request.
+ * @param subId The subId of the subscription to register for provision state changes.
* @param callback The callback to handle the satellite provision state changed event.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void registerForSatelliteProvisionStateChanged(int subId,
- in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
+ int registerForSatelliteProvisionStateChanged(int subId, in ISatelliteStateListener callback);
/**
* Unregister for the satellite provision state change.
*
- * @param subId The subId of the subscription associated with the satellite service.
- * @param errorCallback The callback to get the error code of the request.
+ * @param subId The subId of the subscription to unregister for provision state changes.
* @param callback The callback that was passed to registerForSatelliteProvisionStateChanged.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteProvisionStateChanged(int subId,
- in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
+ int unregisterForSatelliteProvisionStateChanged(int subId, in ISatelliteStateListener callback);
/**
* Request to get whether the device is provisioned with a satellite provider.
@@ -2848,8 +2849,10 @@
/**
* Register for listening to satellite modem state changes.
*
- * @param subId - The subId of the subscription used for listening to satellite state changes.
- * @param callback - The callback to handle the satellite state changed event.
+ * @param subId The subId of the subscription to register for satellite modem state changes.
+ * @param callback The callback to handle the satellite modem state changed event.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
@@ -2858,8 +2861,10 @@
/**
* Unregister to stop listening to satellite modem state changes.
*
- * @param subId - The subId of the subscription associated with the satellite service.
- * @param callback - The callback that was passed to registerForSatelliteStateChange.
+ * @param subId The subId of the subscription to unregister for satellite modem state changes.
+ * @param callback The callback that was passed to registerForSatelliteStateChange.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
@@ -2868,30 +2873,73 @@
/**
* Register to receive incoming datagrams over satellite.
*
- * @param subId - The subId of the subscription used for receiving datagrams.
- * @param datagramType - type of datagram
- * @param callback - The callback to receive incoming datagrams.
+ * @param subId The subId of the subscription to register for incoming satellite datagrams.
+ * @param datagramType Type of datagram.
+ * @param callback The callback to handle receiving incoming datagrams.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
- + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
int registerForSatelliteDatagram(int subId, int datagramType, ISatelliteStateListener callback);
/**
* Unregister to stop receiving incoming datagrams over satellite.
*
- * @param subId - The subId of the subscription associated with the satellite service.
- * @param callback - The callback that was passed to registerForSatelliteDatagram.
+ * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
+ * @param callback The callback that was passed to registerForSatelliteDatagram.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
- + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
int unregisterForSatelliteDatagram(int subId, ISatelliteStateListener callback);
/**
* Poll pending satellite datagrams over satellite.
*
- * @param subId - The subId of the subscription used for receiving datagrams.
+ * @param subId The subId of the subscription to poll pending satellite datagrams for.
+ *
+ * @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
- + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
int pollPendingSatelliteDatagrams(int subId);
+
+ /**
+ * Send datagram over satellite.
+ *
+ * @param subId The subId of the subscription to send satellite datagrams for.
+ * @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);
+
+ /**
+ * Request to get whether satellite communication is allowed for the current location.
+ *
+ * @param subId The subId of the subscription to get whether satellite communication is allowed
+ * for the current location for.
+ * @param receiver Result receiver to get the error code of the request and whether satellite
+ * communication is allowed for the current location.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
+ in ResultReceiver receiver);
+
+ /**
+ * Request to get the time after which the satellite will next be visible.
+ *
+ * @param subId The subId to get the time after which the satellite will next be visible for.
+ * @param receiver Result receiver to get the error code of the request and the requested
+ * time after which the satellite will next be visible.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestTimeForNextSatelliteVisibility(int subId, in ResultReceiver receiver);
}
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/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
index 046174c..1bd8f6a 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -20,12 +20,15 @@
import android.content.pm.ActivityInfo
import android.hardware.display.DisplayManager
import android.util.AttributeSet
+import android.util.Log
+import android.view.Display
import android.view.Window
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.test.silkfx.R
import com.android.test.silkfx.app.WindowObserver
+import java.util.function.Consumer
class ColorModeControls : LinearLayout, WindowObserver {
private val COLOR_MODE_HDR10 = 3
@@ -66,6 +69,38 @@
}
}
+ private val hdrsdrListener = Consumer<Display> { display ->
+ Log.d("SilkFX", "HDR/SDR changed ${display.hdrSdrRatio}")
+ }
+
+ private val displayChangedListener = object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {
+ Log.d("SilkFX", "onDisplayAdded")
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ Log.d("SilkFX", "onDisplayRemoved")
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ Log.d("SilkFX", "onDisplayChanged")
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ Log.d("SilkFX", "is hdr/sdr available: ${display.isHdrSdrRatioAvailable}; " +
+ "current ration = ${display.hdrSdrRatio}")
+ display.registerHdrSdrRatioChangedListener({ it.run() }, hdrsdrListener)
+ displayManager.registerDisplayListener(displayChangedListener, handler)
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ display.unregisterHdrSdrRatioChangedListener(hdrsdrListener)
+ displayManager.unregisterDisplayListener(displayChangedListener)
+ }
+
private fun setColorMode(newMode: Int) {
val window = window!!
var sdrWhitepointChanged = false
diff --git a/tests/testables/src/com/android/internal/config/sysui/OWNERS b/tests/testables/src/com/android/internal/config/sysui/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/testables/src/com/android/internal/config/sysui/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
similarity index 68%
rename from services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
rename to tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
index 3b9726e..a8815dc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestFlagResolver.java
+++ b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
@@ -14,22 +14,20 @@
* limitations under the License.
*/
-package com.android.server.notification;
-
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+package com.android.internal.config.sysui;
import java.util.HashMap;
import java.util.Map;
-public class TestFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
- private Map<SystemUiSystemPropertiesFlags.Flag, Boolean> mOverrides = new HashMap<>();
+public class TestableFlagResolver implements SystemUiSystemPropertiesFlags.FlagResolver {
+ private Map<String, Boolean> mOverrides = new HashMap<>();
@Override
public boolean isEnabled(SystemUiSystemPropertiesFlags.Flag flag) {
- return mOverrides.getOrDefault(flag, flag.mDefaultValue);
+ return mOverrides.getOrDefault(flag.mSysPropKey, flag.mDefaultValue);
}
public void setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag, boolean isEnabled) {
- mOverrides.put(flag, isEnabled);
+ mOverrides.put(flag.mSysPropKey, isEnabled);
}
}
diff --git a/tests/testables/tests/com/android/internal/config/sysui/OWNERS b/tests/testables/tests/com/android/internal/config/sysui/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/testables/tests/com/android/internal/config/sysui/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS