Merge "Print the full exception upon widgets inflation error" into sc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 70d0d5d..b3396c5 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -1135,7 +1135,7 @@
this(context, new Injector(context));
}
- private static boolean isRtc(int type) {
+ static boolean isRtc(int type) {
return (type == RTC || type == RTC_WAKEUP);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index 2dc131c..4e7311f 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -72,7 +72,8 @@
alarmStore.getCount(
a -> (a.getRequestedElapsed() > now + INDEFINITE_DELAY)),
alarmStore.getCount(a -> (a.repeatInterval != 0)),
- alarmStore.getCount(a -> (a.alarmClock != null))
+ alarmStore.getCount(a -> (a.alarmClock != null)),
+ alarmStore.getCount(a -> AlarmManagerService.isRtc(a.type))
));
return StatsManager.PULL_SUCCESS;
}
@@ -101,7 +102,8 @@
(a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0,
a.alarmClock != null,
a.repeatInterval != 0,
- reasonToStatsReason(a.mExactAllowReason));
+ reasonToStatsReason(a.mExactAllowReason),
+ AlarmManagerService.isRtc(a.type));
}
static void pushAlarmBatchDelivered(int numAlarms, int wakeups) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 3322841..80e9e2d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -621,6 +621,7 @@
}
@Override
+ @GuardedBy("mLock")
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
final long nowElapsed = sElapsedRealtimeClock.millis();
final int userId = jobStatus.getSourceUserId();
@@ -648,6 +649,7 @@
}
@Override
+ @GuardedBy("mLock")
public void prepareForExecutionLocked(JobStatus jobStatus) {
if (DEBUG) {
Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
@@ -676,6 +678,7 @@
}
@Override
+ @GuardedBy("mLock")
public void unprepareFromExecutionLocked(JobStatus jobStatus) {
Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
if (timer != null) {
@@ -691,6 +694,7 @@
}
@Override
+ @GuardedBy("mLock")
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate) {
if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) {
@@ -796,10 +800,12 @@
}
/** Returns the maximum amount of time this job could run for. */
+ @GuardedBy("mLock")
public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) {
if (!jobStatus.shouldTreatAsExpeditedJob()) {
- // If quota is currently "free", then the job can run for the full amount of time.
- if (mChargeTracker.isCharging()
+ // If quota is currently "free", then the job can run for the full amount of time,
+ // regardless of bucket (hence using charging instead of isQuotaFreeLocked()).
+ if (mChargeTracker.isChargingLocked()
|| mTopAppCache.get(jobStatus.getSourceUid())
|| isTopStartedJobLocked(jobStatus)
|| isUidInForeground(jobStatus.getSourceUid())) {
@@ -810,7 +816,7 @@
}
// Expedited job.
- if (mChargeTracker.isCharging()) {
+ if (mChargeTracker.isChargingLocked()) {
return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
}
if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) {
@@ -828,8 +834,9 @@
}
/** @return true if the job is within expedited job quota. */
+ @GuardedBy("mLock")
public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) {
- if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) {
+ if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) {
return true;
}
// A job is within quota if one of the following is true:
@@ -887,9 +894,10 @@
jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
}
- private boolean isQuotaFree(final int standbyBucket) {
+ @GuardedBy("mLock")
+ private boolean isQuotaFreeLocked(final int standbyBucket) {
// Quota constraint is not enforced while charging.
- if (mChargeTracker.isCharging()) {
+ if (mChargeTracker.isChargingLocked()) {
// Restricted jobs require additional constraints when charging, so don't immediately
// mark quota as free when charging.
return standbyBucket != RESTRICTED_INDEX;
@@ -898,11 +906,12 @@
}
@VisibleForTesting
+ @GuardedBy("mLock")
boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
final int standbyBucket) {
if (standbyBucket == NEVER_INDEX) return false;
- if (isQuotaFree(standbyBucket)) return true;
+ if (isQuotaFreeLocked(standbyBucket)) return true;
ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
return getRemainingExecutionTimeLocked(stats) > 0
@@ -1493,13 +1502,14 @@
/** Schedule a cleanup alarm if necessary and there isn't already one scheduled. */
@VisibleForTesting
void maybeScheduleCleanupAlarmLocked() {
- if (mNextCleanupTimeElapsed > sElapsedRealtimeClock.millis()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (mNextCleanupTimeElapsed > nowElapsed) {
// There's already an alarm scheduled. Just stick with that one. There's no way we'll
// end up scheduling an earlier alarm.
if (DEBUG) {
Slog.v(TAG, "Not scheduling cleanup since there's already one at "
- + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed
- - sElapsedRealtimeClock.millis()) + "ms)");
+ + mNextCleanupTimeElapsed
+ + " (in " + (mNextCleanupTimeElapsed - nowElapsed) + "ms)");
}
return;
}
@@ -1521,7 +1531,7 @@
if (nextCleanupElapsed - mNextCleanupTimeElapsed <= 10 * MINUTE_IN_MILLIS) {
// No need to clean up too often. Delay the alarm if the next cleanup would be too soon
// after it.
- nextCleanupElapsed += 10 * MINUTE_IN_MILLIS;
+ nextCleanupElapsed = mNextCleanupTimeElapsed + 10 * MINUTE_IN_MILLIS;
}
mNextCleanupTimeElapsed = nextCleanupElapsed;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextCleanupElapsed, ALARM_TAG_CLEANUP,
@@ -1556,9 +1566,9 @@
private void handleNewChargingStateLocked() {
mTimerChargingUpdateFunctor.setStatus(sElapsedRealtimeClock.millis(),
- mChargeTracker.isCharging());
+ mChargeTracker.isChargingLocked());
if (DEBUG) {
- Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging());
+ Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isChargingLocked());
}
// Deal with Timers first.
mEJPkgTimers.forEach(mTimerChargingUpdateFunctor);
@@ -1827,6 +1837,7 @@
* Track whether we're charging. This has a slightly different definition than that of
* BatteryController.
*/
+ @GuardedBy("mLock")
private boolean mCharging;
ChargingTracker() {
@@ -1846,7 +1857,8 @@
mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
}
- public boolean isCharging() {
+ @GuardedBy("mLock")
+ public boolean isChargingLocked() {
return mCharging;
}
@@ -2055,9 +2067,12 @@
}
return;
}
- if (mRunningBgJobs.remove(jobStatus)
- && !mChargeTracker.isCharging() && mRunningBgJobs.size() == 0) {
- emitSessionLocked(sElapsedRealtimeClock.millis());
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final int standbyBucket = JobSchedulerService.standbyBucketForPackage(
+ mPkg.packageName, mPkg.userId, nowElapsed);
+ if (mRunningBgJobs.remove(jobStatus) && mRunningBgJobs.size() == 0
+ && !isQuotaFreeLocked(standbyBucket)) {
+ emitSessionLocked(nowElapsed);
cancelCutoff();
}
}
@@ -2077,6 +2092,7 @@
cancelCutoff();
}
+ @GuardedBy("mLock")
private void emitSessionLocked(long nowElapsed) {
if (mBgJobCount <= 0) {
// Nothing to emit.
@@ -2121,6 +2137,7 @@
}
}
+ @GuardedBy("mLock")
private boolean shouldTrackLocked() {
final long nowElapsed = sElapsedRealtimeClock.millis();
final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName,
@@ -2132,7 +2149,7 @@
final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid);
final boolean hasTopAppExemption = !mRegularJobTimer
&& (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed);
- return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging())
+ return !isQuotaFreeLocked(standbyBucket)
&& !mForegroundUids.get(mUid) && !hasTempAllowlistExemption
&& !hasTopAppExemption;
}
@@ -2462,30 +2479,60 @@
}
}
- private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> {
- private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() {
- public boolean test(TimingSession ts) {
- return ts.endTimeElapsed <= sElapsedRealtimeClock.millis() - MAX_PERIOD_MS;
- }
- };
+ private static final class TimingSessionTooOldPredicate implements Predicate<TimingSession> {
+ private long mNowElapsed;
+
+ private void updateNow() {
+ mNowElapsed = sElapsedRealtimeClock.millis();
+ }
@Override
- public void accept(List<TimingSession> sessions) {
- if (sessions != null) {
- // Remove everything older than MAX_PERIOD_MS time ago.
- sessions.removeIf(mTooOld);
- }
+ public boolean test(TimingSession ts) {
+ return ts.endTimeElapsed <= mNowElapsed - MAX_PERIOD_MS;
}
}
- private final DeleteTimingSessionsFunctor mDeleteOldSessionsFunctor =
- new DeleteTimingSessionsFunctor();
+ private final TimingSessionTooOldPredicate mTimingSessionTooOld =
+ new TimingSessionTooOldPredicate();
+
+ private final Consumer<List<TimingSession>> mDeleteOldSessionsFunctor = sessions -> {
+ if (sessions != null) {
+ // Remove everything older than MAX_PERIOD_MS time ago.
+ sessions.removeIf(mTimingSessionTooOld);
+ }
+ };
@VisibleForTesting
void deleteObsoleteSessionsLocked() {
+ mTimingSessionTooOld.updateNow();
+
+ // Regular sessions
mTimingSessions.forEach(mDeleteOldSessionsFunctor);
- // Don't delete EJ timing sessions here. They'll be removed in
- // getRemainingEJExecutionTimeLocked().
+
+ // EJ sessions
+ for (int uIdx = 0; uIdx < mEJTimingSessions.numMaps(); ++uIdx) {
+ final int userId = mEJTimingSessions.keyAt(uIdx);
+ for (int pIdx = 0; pIdx < mEJTimingSessions.numElementsForKey(userId); ++pIdx) {
+ final String packageName = mEJTimingSessions.keyAt(uIdx, pIdx);
+ final ShrinkableDebits debits = getEJDebitsLocked(userId, packageName);
+ final List<TimingSession> sessions = mEJTimingSessions.get(userId, packageName);
+ if (sessions == null) {
+ continue;
+ }
+
+ while (sessions.size() > 0) {
+ final TimingSession ts = sessions.get(0);
+ if (mTimingSessionTooOld.test(ts)) {
+ // Stale sessions may still be factored into tally. Remove them.
+ final long duration = ts.endTimeElapsed - ts.startTimeElapsed;
+ debits.transactLocked(-duration);
+ sessions.remove(0);
+ } else {
+ break;
+ }
+ }
+ }
+ }
}
private class QcHandler extends Handler {
@@ -4054,7 +4101,7 @@
@Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
- pw.println("Is charging: " + mChargeTracker.isCharging());
+ pw.println("Is charging: " + mChargeTracker.isChargingLocked());
pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
pw.println();
@@ -4231,7 +4278,8 @@
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.QUOTA);
- proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
+ proto.write(StateControllerProto.QuotaController.IS_CHARGING,
+ mChargeTracker.isChargingLocked());
proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME,
sElapsedRealtimeClock.millis());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index 3c4961a..140cca6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
@@ -56,7 +56,7 @@
private boolean mDockIdle;
private boolean mProjectionActive;
private IdlenessListener mIdleListener;
- private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener =
+ private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener =
this::onProjectionStateChanged;
private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> {
@@ -105,9 +105,9 @@
// TODO(b/172579710): Move the callbacks off the main executor and on to
// JobSchedulerBackgroundThread.getExecutor() once synchronization is fixed in this class.
- context.getSystemService(UiModeManager.class).addOnProjectionStateChangeListener(
+ context.getSystemService(UiModeManager.class).addOnProjectionStateChangedListener(
UiModeManager.PROJECTION_TYPE_ALL, context.getMainExecutor(),
- mOnProjectionStateChangeListener);
+ mOnProjectionStateChangedListener);
}
private void onProjectionStateChanged(@UiModeManager.ProjectionType int activeProjectionTypes,
diff --git a/core/api/current.txt b/core/api/current.txt
index 82264c1..de92fd1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1821,7 +1821,6 @@
field public static final int notification_large_icon_width = 17104901; // 0x1050005
field public static final int system_app_widget_background_radius;
field public static final int system_app_widget_inner_radius;
- field public static final int system_app_widget_internal_padding;
field public static final int thumbnail_height = 17104897; // 0x1050001
field public static final int thumbnail_width = 17104898; // 0x1050002
}
@@ -52965,7 +52964,7 @@
public interface UiTranslationStateCallback {
method public void onFinished();
method public void onPaused();
- method public void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
+ method public default void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
method @Deprecated public void onStarted(@NonNull String, @NonNull String);
method public default void onStarted(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
}
diff --git a/core/api/removed.txt b/core/api/removed.txt
index cdaa5f53..8229019a 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -1,4 +1,12 @@
// Signature format: 2.0
+package android {
+
+ public static final class R.dimen {
+ field public static final int __removed_system_app_widget_internal_padding;
+ }
+
+}
+
package android.app {
public class Notification implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bffd0e7..e80615a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -838,12 +838,12 @@
}
public class UiModeManager {
- method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void addOnProjectionStateChangeListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.app.UiModeManager.OnProjectionStateChangeListener);
+ method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void addOnProjectionStateChangedListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.app.UiModeManager.OnProjectionStateChangedListener);
method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public int getActiveProjectionTypes();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public java.util.Set<java.lang.String> getProjectingPackages(int);
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean releaseProjection(int);
- method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void removeOnProjectionStateChangeListener(@NonNull android.app.UiModeManager.OnProjectionStateChangeListener);
+ method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void removeOnProjectionStateChangedListener(@NonNull android.app.UiModeManager.OnProjectionStateChangedListener);
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean requestProjection(int);
field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
@@ -855,7 +855,7 @@
field public static final int PROJECTION_TYPE_NONE = 0; // 0x0
}
- public static interface UiModeManager.OnProjectionStateChangeListener {
+ public static interface UiModeManager.OnProjectionStateChangedListener {
method public void onProjectionStateChanged(int, @NonNull java.util.Set<java.lang.String>);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4975fc2..010f4e4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -9038,8 +9038,11 @@
*
* @hide
*/
- // TODO (b/186872903) Refactor how sync noted ops are propagaged.
+ // TODO (b/186872903) Refactor how sync noted ops are propagated.
public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) {
+ if (!isListeningForOpNotedInBinderTransaction()) {
+ return;
+ }
final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps =
sAppOpsNotedInThisBinderTransaction.get();
if (notedAppOps == null) {
@@ -9083,9 +9086,6 @@
}
final String myPackageName = ActivityThread.currentPackageName();
- if (myPackageName == null) {
- return;
- }
synchronized (sLock) {
for (int i = 0; i < packageCount; i++) {
@@ -9105,7 +9105,7 @@
final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (myPackageName.equals(packageName)) {
+ if (Objects.equals(myPackageName, packageName)) {
if (sOnOpNotedCallback != null) {
sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code,
attributionTag, packageName));
@@ -9123,7 +9123,7 @@
}
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (myPackageName.equals(packageName)) {
+ if (Objects.equals(myPackageName, packageName)) {
sMessageCollector.onNoted(new SyncNotedAppOp(code,
attributionTag, packageName));
}
diff --git a/core/java/android/app/IOnProjectionStateChangeListener.aidl b/core/java/android/app/IOnProjectionStateChangedListener.aidl
similarity index 93%
rename from core/java/android/app/IOnProjectionStateChangeListener.aidl
rename to core/java/android/app/IOnProjectionStateChangedListener.aidl
index f154985..2d2bf7f 100644
--- a/core/java/android/app/IOnProjectionStateChangeListener.aidl
+++ b/core/java/android/app/IOnProjectionStateChangedListener.aidl
@@ -17,6 +17,6 @@
package android.app;
/** {@hide} */
-oneway interface IOnProjectionStateChangeListener {
+oneway interface IOnProjectionStateChangedListener {
void onProjectionStateChanged(int activeProjectionTypes, in List<String> projectingPackages);
}
\ No newline at end of file
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index f71eebdc..9f21bcc 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -16,7 +16,7 @@
package android.app;
-import android.app.IOnProjectionStateChangeListener;
+import android.app.IOnProjectionStateChangedListener;
/**
* Interface used to control special UI modes.
@@ -119,12 +119,12 @@
/**
* Registers a listener for changes to projection state.
*/
- void addOnProjectionStateChangeListener(in IOnProjectionStateChangeListener listener, int projectionType);
+ void addOnProjectionStateChangedListener(in IOnProjectionStateChangedListener listener, int projectionType);
/**
* Unregisters a listener for changes to projection state.
*/
- void removeOnProjectionStateChangeListener(in IOnProjectionStateChangeListener listener);
+ void removeOnProjectionStateChangedListener(in IOnProjectionStateChangedListener listener);
/**
* Returns packages that have currently set the given projection type.
diff --git a/core/java/android/app/PictureInPictureUiState.java b/core/java/android/app/PictureInPictureUiState.java
index 3d2cb3f..32ce89a 100644
--- a/core/java/android/app/PictureInPictureUiState.java
+++ b/core/java/android/app/PictureInPictureUiState.java
@@ -42,7 +42,20 @@
}
/**
- * Returns whether Picture-in-Picture is stashed or not.
+ * Returns whether Picture-in-Picture is stashed or not. A stashed PiP means it is only
+ * partially visible to the user, with some parts of it being off-screen. This is usually
+ * an UI state that is triggered by the user, such as flinging the PiP to the edge or letting go
+ * of PiP while dragging partially off-screen.
+ *
+ * Developers can use this in conjunction with
+ * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} to get a signal
+ * when the PiP stash state has changed. For example, if the state changed from {@code false} to
+ * {@code true}, developers can choose to temporarily pause video playback if PiP is of video
+ * content. Vice versa, if changing from {@code true} to {@code false} and video content is
+ * paused, developers can resumevideo playback.
+ *
+ * @see <a href="http://developer.android.com/about/versions/12/features/pip-improvements">
+ * Picture in Picture (PiP) improvements</a>
*/
public boolean isStashed() {
return mIsStashed;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 24fd04b..973a8fb 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -79,7 +79,7 @@
* @hide
*/
@SystemApi
- public interface OnProjectionStateChangeListener {
+ public interface OnProjectionStateChangedListener {
/**
* Callback invoked when projection state changes for a {@link ProjectionType} for which
* this listener was added.
@@ -254,10 +254,10 @@
private final Object mLock = new Object();
/**
* Map that stores internally created {@link InnerListener} objects keyed by their corresponding
- * externally provided {@link OnProjectionStateChangeListener} objects.
+ * externally provided callback objects.
*/
@GuardedBy("mLock")
- private final Map<OnProjectionStateChangeListener, InnerListener>
+ private final Map<OnProjectionStateChangedListener, InnerListener>
mProjectionStateListenerMap = new ArrayMap<>();
/**
@@ -265,9 +265,9 @@
* fail to remove listeners.
*/
@GuardedBy("mLock")
- private final OnProjectionStateChangeListenerResourceManager
- mOnProjectionStateChangeListenerResourceManager =
- new OnProjectionStateChangeListenerResourceManager();
+ private final OnProjectionStateChangedListenerResourceManager
+ mOnProjectionStateChangedListenerResourceManager =
+ new OnProjectionStateChangedListenerResourceManager();
@UnsupportedAppUsage
/*package*/ UiModeManager() throws ServiceNotFoundException {
@@ -687,7 +687,7 @@
/**
* Indicates no projection type. Can be used to compare with the {@link ProjectionType} in
- * {@link OnProjectionStateChangeListener#onProjectionStateChanged(int, Set)}.
+ * {@link OnProjectionStateChangedListener#onProjectionStateChanged(int, Set)}.
*
* @hide
*/
@@ -706,7 +706,7 @@
public static final int PROJECTION_TYPE_AUTOMOTIVE = 0x0001;
/**
* Indicates all projection types. For use with
- * {@link #addOnProjectionStateChangeListener(int, Executor, OnProjectionStateChangeListener)}
+ * {@link #addOnProjectionStateChangedListener(int, Executor, OnProjectionStateChangedListener)}
* and {@link #getProjectingPackages(int)}.
*
* @hide
@@ -829,15 +829,15 @@
*
* @param projectionType one or more {@link ProjectionType}s to listen for changes regarding
* @param executor an {@link Executor} on which to invoke the callbacks
- * @param listener the {@link OnProjectionStateChangeListener} to add
+ * @param listener the {@link OnProjectionStateChangedListener} to add
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
- public void addOnProjectionStateChangeListener(@ProjectionType int projectionType,
+ public void addOnProjectionStateChangedListener(@ProjectionType int projectionType,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnProjectionStateChangeListener listener) {
+ @NonNull OnProjectionStateChangedListener listener) {
synchronized (mLock) {
if (mProjectionStateListenerMap.containsKey(listener)) {
Slog.i(TAG, "Attempted to add listener that was already added.");
@@ -845,12 +845,12 @@
}
if (mService != null) {
InnerListener innerListener = new InnerListener(executor, listener,
- mOnProjectionStateChangeListenerResourceManager);
+ mOnProjectionStateChangedListenerResourceManager);
try {
- mService.addOnProjectionStateChangeListener(innerListener, projectionType);
+ mService.addOnProjectionStateChangedListener(innerListener, projectionType);
mProjectionStateListenerMap.put(listener, innerListener);
} catch (RemoteException e) {
- mOnProjectionStateChangeListenerResourceManager.remove(innerListener);
+ mOnProjectionStateChangedListenerResourceManager.remove(innerListener);
throw e.rethrowFromSystemServer();
}
}
@@ -860,14 +860,14 @@
/**
* Removes the listener so it stops receiving updates for all {@link ProjectionType}s.
*
- * @param listener the {@link OnProjectionStateChangeListener} to remove
+ * @param listener the {@link OnProjectionStateChangedListener} to remove
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
- public void removeOnProjectionStateChangeListener(
- @NonNull OnProjectionStateChangeListener listener) {
+ public void removeOnProjectionStateChangedListener(
+ @NonNull OnProjectionStateChangedListener listener) {
synchronized (mLock) {
InnerListener innerListener = mProjectionStateListenerMap.get(listener);
if (innerListener == null) {
@@ -876,23 +876,23 @@
}
if (mService != null) {
try {
- mService.removeOnProjectionStateChangeListener(innerListener);
+ mService.removeOnProjectionStateChangedListener(innerListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
mProjectionStateListenerMap.remove(listener);
- mOnProjectionStateChangeListenerResourceManager.remove(innerListener);
+ mOnProjectionStateChangedListenerResourceManager.remove(innerListener);
}
}
- private static class InnerListener extends IOnProjectionStateChangeListener.Stub {
- private final WeakReference<OnProjectionStateChangeListenerResourceManager>
+ private static class InnerListener extends IOnProjectionStateChangedListener.Stub {
+ private final WeakReference<OnProjectionStateChangedListenerResourceManager>
mResourceManager;
private InnerListener(@NonNull Executor executor,
- @NonNull OnProjectionStateChangeListener outerListener,
- @NonNull OnProjectionStateChangeListenerResourceManager resourceManager) {
+ @NonNull OnProjectionStateChangedListener outerListener,
+ @NonNull OnProjectionStateChangedListenerResourceManager resourceManager) {
resourceManager.put(this, executor, outerListener);
mResourceManager = new WeakReference<>(resourceManager);
}
@@ -900,13 +900,14 @@
@Override
public void onProjectionStateChanged(int activeProjectionTypes,
List<String> projectingPackages) {
- OnProjectionStateChangeListenerResourceManager resourceManager = mResourceManager.get();
+ OnProjectionStateChangedListenerResourceManager resourceManager =
+ mResourceManager.get();
if (resourceManager == null) {
Slog.w(TAG, "Can't execute onProjectionStateChanged, resource manager is gone.");
return;
}
- OnProjectionStateChangeListener outerListener = resourceManager.getOuterListener(this);
+ OnProjectionStateChangedListener outerListener = resourceManager.getOuterListener(this);
Executor executor = resourceManager.getExecutor(this);
if (outerListener == null || executor == null) {
Slog.w(TAG, "Can't execute onProjectionStatechanged, references are null.");
@@ -914,7 +915,7 @@
}
executor.execute(PooledLambda.obtainRunnable(
- OnProjectionStateChangeListener::onProjectionStateChanged,
+ OnProjectionStateChangedListener::onProjectionStateChanged,
outerListener,
activeProjectionTypes,
new ArraySet<>(projectingPackages)).recycleOnUse());
@@ -924,15 +925,15 @@
/**
* Wrapper class that ensures we don't leak {@link Activity} or other large {@link Context} in
* which this {@link UiModeManager} resides if/when it ends without unregistering associated
- * {@link OnProjectionStateChangeListener}s.
+ * callback objects.
*/
- private static class OnProjectionStateChangeListenerResourceManager {
- private final Map<InnerListener, OnProjectionStateChangeListener> mOuterListenerMap =
+ private static class OnProjectionStateChangedListenerResourceManager {
+ private final Map<InnerListener, OnProjectionStateChangedListener> mOuterListenerMap =
new ArrayMap<>(1);
private final Map<InnerListener, Executor> mExecutorMap = new ArrayMap<>(1);
void put(@NonNull InnerListener innerListener, @NonNull Executor executor,
- OnProjectionStateChangeListener outerListener) {
+ OnProjectionStateChangedListener outerListener) {
mOuterListenerMap.put(innerListener, outerListener);
mExecutorMap.put(innerListener, executor);
}
@@ -942,7 +943,7 @@
mExecutorMap.remove(innerListener);
}
- OnProjectionStateChangeListener getOuterListener(@NonNull InnerListener innerListener) {
+ OnProjectionStateChangedListener getOuterListener(@NonNull InnerListener innerListener) {
return mOuterListenerMap.get(innerListener);
}
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 8462cbe..6acbef2 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -3,9 +3,9 @@
# Android Enterprise team
rubinxu@google.com
sandness@google.com
-eranm@google.com
alexkershaw@google.com
pgrafov@google.com
# Emeritus
yamasani@google.com
+eranm@google.com
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 0142156..152de44 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -17,6 +17,7 @@
package android.appwidget;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityOptions;
import android.compat.annotation.UnsupportedAppUsage;
@@ -68,6 +69,7 @@
static final String TAG = "AppWidgetHostView";
private static final String KEY_JAILED_ARRAY = "jail";
+ private static final String KEY_INFLATION_ID = "inflation_id";
static final boolean LOGD = false;
@@ -97,9 +99,12 @@
private RemoteViews.ColorResources mColorResources = null;
// Stores the last remote views last inflated.
private RemoteViews mLastInflatedRemoteViews = null;
+ private long mLastInflatedRemoteViewsId = -1;
private Executor mAsyncExecutor;
private CancellationSignal mLastExecutionSignal;
+ private SparseArray<Parcelable> mDelayedRestoredState;
+ private long mDelayedRestoredInflationId;
/**
* Create a host view. Uses default fade animations.
@@ -226,6 +231,8 @@
Bundle bundle = new Bundle();
bundle.putSparseParcelableArray(KEY_JAILED_ARRAY, jail);
+ bundle.putLong(KEY_INFLATION_ID, mLastInflatedRemoteViewsId);
+ container.put(generateId(), bundle);
container.put(generateId(), bundle);
}
@@ -239,14 +246,30 @@
final Parcelable parcelable = container.get(generateId());
SparseArray<Parcelable> jail = null;
+ long inflationId = -1;
if (parcelable instanceof Bundle) {
- jail = ((Bundle) parcelable).getSparseParcelableArray(KEY_JAILED_ARRAY);
+ Bundle bundle = (Bundle) parcelable;
+ jail = bundle.getSparseParcelableArray(KEY_JAILED_ARRAY);
+ inflationId = bundle.getLong(KEY_INFLATION_ID, -1);
}
if (jail == null) jail = new SparseArray<>();
+ mDelayedRestoredState = jail;
+ mDelayedRestoredInflationId = inflationId;
+ restoreInstanceState();
+ }
+
+ void restoreInstanceState() {
+ long inflationId = mDelayedRestoredInflationId;
+ SparseArray<Parcelable> state = mDelayedRestoredState;
+ if (inflationId == -1 || inflationId != mLastInflatedRemoteViewsId) {
+ return; // We don't restore.
+ }
+ mDelayedRestoredInflationId = -1;
+ mDelayedRestoredState = null;
try {
- super.dispatchRestoreInstanceState(jail);
+ super.dispatchRestoreInstanceState(state);
} catch (Exception e) {
Log.e(TAG, "failed to restoreInstanceState for widget id: " + mAppWidgetId + ", "
+ (mInfo == null ? "null" : mInfo.provider), e);
@@ -476,7 +499,7 @@
* AppWidget provider. Will animate into these new views as needed
*/
public void updateAppWidget(RemoteViews remoteViews) {
- this.mLastInflatedRemoteViews = remoteViews;
+ mLastInflatedRemoteViews = remoteViews;
applyRemoteViews(remoteViews, true);
}
@@ -484,17 +507,23 @@
* Reapply the last inflated remote views, or the default view is none was inflated.
*/
private void reapplyLastRemoteViews() {
+ SparseArray<Parcelable> savedState = new SparseArray<>();
+ saveHierarchyState(savedState);
applyRemoteViews(mLastInflatedRemoteViews, true);
+ restoreHierarchyState(savedState);
}
/**
* @hide
*/
- protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) {
+ protected void applyRemoteViews(@Nullable RemoteViews remoteViews, boolean useAsyncIfPossible) {
boolean recycled = false;
View content = null;
Exception exception = null;
+ // Block state restore until the end of the apply.
+ mLastInflatedRemoteViewsId = -1;
+
if (mLastExecutionSignal != null) {
mLastExecutionSignal.cancel();
mLastExecutionSignal = null;
@@ -525,6 +554,7 @@
rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
mColorResources);
content = mView;
+ mLastInflatedRemoteViewsId = rvToApply.computeUniqueId(remoteViews);
recycled = true;
if (LOGD) Log.d(TAG, "was able to recycle existing layout");
} catch (RuntimeException e) {
@@ -537,6 +567,7 @@
try {
content = rvToApply.apply(mContext, this, mInteractionHandler,
mCurrentSize, mColorResources);
+ mLastInflatedRemoteViewsId = rvToApply.computeUniqueId(remoteViews);
if (LOGD) Log.d(TAG, "had to inflate new layout");
} catch (RuntimeException e) {
exception = e;
@@ -574,12 +605,16 @@
}
}
- private void inflateAsync(RemoteViews remoteViews) {
+ private void inflateAsync(@NonNull RemoteViews remoteViews) {
// Prepare a local reference to the remote Context so we're ready to
// inflate any requested LayoutParams.
mRemoteContext = getRemoteContext();
int layoutId = remoteViews.getLayoutId();
+ if (mLastExecutionSignal != null) {
+ mLastExecutionSignal.cancel();
+ }
+
// If our stale view has been prepared to match active, and the new
// layout matches, try recycling it
if (layoutId == mLayoutId && mView != null) {
@@ -611,7 +646,10 @@
private final boolean mIsReapply;
private final int mLayoutId;
- public ViewApplyListener(RemoteViews views, int layoutId, boolean isReapply) {
+ ViewApplyListener(
+ RemoteViews views,
+ int layoutId,
+ boolean isReapply) {
mViews = views;
mLayoutId = layoutId;
mIsReapply = isReapply;
@@ -623,6 +661,10 @@
mViewMode = VIEW_MODE_CONTENT;
applyContent(v, mIsReapply, null);
+
+ mLastInflatedRemoteViewsId = mViews.computeUniqueId(mLastInflatedRemoteViews);
+ restoreInstanceState();
+ mLastExecutionSignal = null;
}
@Override
@@ -638,6 +680,7 @@
} else {
applyContent(null, false, e);
}
+ mLastExecutionSignal = null;
}
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 51d196d..17116e2 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -223,14 +223,6 @@
public static final long BLOCK_FLAG_SLIPPERY = android.os.IInputConstants.BLOCK_FLAG_SLIPPERY;
/**
- * Check whether apps are using MotionEvent.getRawX/Y. This is implementation-specific, and
- * thus undefined for most 3p app usages.
- * @hide
- */
- @ChangeId
- public static final long APP_USES_RAW_INPUT_COORDS = 179274888L;
-
- /**
* Input Event Injection Synchronization Mode: None.
* Never blocks. Injection is asynchronous and is assumed always to be successful.
* @hide
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 31ca8e1..b054468 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -16,7 +16,6 @@
package android.view;
-import static android.hardware.input.InputManager.APP_USES_RAW_INPUT_COORDS;
import static android.view.Display.DEFAULT_DISPLAY;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -24,7 +23,6 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.compat.Compatibility;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Matrix;
import android.os.Build;
@@ -1569,6 +1567,8 @@
int axis, int pointerIndex, int historyPos);
@FastNative
private static native void nativeTransform(long nativePtr, Matrix matrix);
+ @FastNative
+ private static native void nativeApplyTransform(long nativePtr, Matrix matrix);
// -------------- @CriticalNative ----------------------
@@ -2674,7 +2674,6 @@
* @see #AXIS_X
*/
public final float getRawX() {
- Compatibility.reportUnconditionalChange(APP_USES_RAW_INPUT_COORDS);
return nativeGetRawAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
}
@@ -2688,7 +2687,6 @@
* @see #AXIS_Y
*/
public final float getRawY() {
- Compatibility.reportUnconditionalChange(APP_USES_RAW_INPUT_COORDS);
return nativeGetRawAxisValue(mNativePtr, AXIS_Y, 0, HISTORY_CURRENT);
}
@@ -2705,7 +2703,6 @@
* @see #AXIS_X
*/
public float getRawX(int pointerIndex) {
- Compatibility.reportUnconditionalChange(APP_USES_RAW_INPUT_COORDS);
return nativeGetRawAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
}
@@ -2722,7 +2719,6 @@
* @see #AXIS_Y
*/
public float getRawY(int pointerIndex) {
- Compatibility.reportUnconditionalChange(APP_USES_RAW_INPUT_COORDS);
return nativeGetRawAxisValue(mNativePtr, AXIS_Y, pointerIndex, HISTORY_CURRENT);
}
@@ -3266,6 +3262,21 @@
}
/**
+ * Transforms all of the points in the event directly instead of modifying the event's
+ * internal transform.
+ *
+ * @param matrix The transformation matrix to apply.
+ * @hide
+ */
+ public void applyTransform(Matrix matrix) {
+ if (matrix == null) {
+ throw new IllegalArgumentException("matrix must not be null");
+ }
+
+ nativeApplyTransform(mNativePtr, matrix);
+ }
+
+ /**
* Add a new movement to the batch of movements in this event. The event's
* current location, position and size is updated to the new values.
* The current values in the event are added to a list of historical values.
diff --git a/core/java/android/view/translation/UiTranslationStateCallback.java b/core/java/android/view/translation/UiTranslationStateCallback.java
index 968cbdc..1bae0ef 100644
--- a/core/java/android/view/translation/UiTranslationStateCallback.java
+++ b/core/java/android/view/translation/UiTranslationStateCallback.java
@@ -54,7 +54,9 @@
* The system is requesting that the application restore from the temporarily paused state and
* show the content in translated language.
*/
- void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale);
+ // TODO: Remove the default implementation when clients have implemented this.
+ default void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale) {
+ }
/**
* The UI Translation session has ended.
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 6b49569..ad123c1 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -16,10 +16,10 @@
package android.webkit;
-import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.UptimeMillisLong;
import android.app.ActivityThread;
import android.app.Application;
import android.app.ResourcesManager;
@@ -227,7 +227,7 @@
* WebViewChromiumFactoryProvider#create method was invoked.
*/
@NonNull
- @ElapsedRealtimeLong
+ @UptimeMillisLong
public long[] getTimestamps() {
return WebViewFactory.getTimestamps();
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 5fc5b29..9a38512 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -273,7 +273,7 @@
// us honest and minimize usage of WebView internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
- sTimestamps[WEBVIEW_LOAD_START] = SystemClock.elapsedRealtime();
+ sTimestamps[WEBVIEW_LOAD_START] = SystemClock.uptimeMillis();
final int uid = android.os.Process.myUid();
if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID
|| uid == android.os.Process.PHONE_UID || uid == android.os.Process.NFC_UID
@@ -413,7 +413,7 @@
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
"initialApplication.createApplicationContext");
- sTimestamps[CREATE_CONTEXT_START] = SystemClock.elapsedRealtime();
+ sTimestamps[CREATE_CONTEXT_START] = SystemClock.uptimeMillis();
try {
// Construct an app context to load the Java code into the current app.
Context webViewContext = initialApplication.createApplicationContext(
@@ -422,7 +422,7 @@
sPackageInfo = newPackageInfo;
return webViewContext;
} finally {
- sTimestamps[CREATE_CONTEXT_END] = SystemClock.elapsedRealtime();
+ sTimestamps[CREATE_CONTEXT_END] = SystemClock.uptimeMillis();
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (RemoteException | PackageManager.NameNotFoundException e) {
@@ -448,26 +448,26 @@
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
- sTimestamps[ADD_ASSETS_START] = SystemClock.elapsedRealtime();
+ sTimestamps[ADD_ASSETS_START] = SystemClock.uptimeMillis();
for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) {
initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
}
sTimestamps[ADD_ASSETS_END] = sTimestamps[GET_CLASS_LOADER_START] =
- SystemClock.elapsedRealtime();
+ SystemClock.uptimeMillis();
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
sTimestamps[GET_CLASS_LOADER_END] = sTimestamps[NATIVE_LOAD_START] =
- SystemClock.elapsedRealtime();
+ SystemClock.uptimeMillis();
WebViewLibraryLoader.loadNativeLibrary(clazzLoader,
getWebViewLibrary(sPackageInfo.applicationInfo));
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
sTimestamps[NATIVE_LOAD_END] = sTimestamps[PROVIDER_CLASS_FOR_NAME_START] =
- SystemClock.elapsedRealtime();
+ SystemClock.uptimeMillis();
try {
return getWebViewProviderClass(clazzLoader);
} finally {
- sTimestamps[PROVIDER_CLASS_FOR_NAME_END] = SystemClock.elapsedRealtime();
+ sTimestamps[PROVIDER_CLASS_FOR_NAME_END] = SystemClock.uptimeMillis();
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (ClassNotFoundException e) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0dbdb8f..ee7818c 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -385,6 +385,11 @@
*/
private int mViewId = View.NO_ID;
+ /**
+ * Id used to uniquely identify a {@link RemoteViews} instance coming from a given provider.
+ */
+ private long mProviderInstanceId = -1;
+
/** Class cookies of the Parcel this instance was read from. */
private Map<Class, Object> mClassCookies;
@@ -3646,6 +3651,7 @@
mApplyFlags = src.mApplyFlags;
mClassCookies = src.mClassCookies;
mIdealSize = src.mIdealSize;
+ mProviderInstanceId = src.mProviderInstanceId;
if (src.hasLandscapeAndPortraitLayouts()) {
mLandscape = new RemoteViews(src.mLandscape);
@@ -3744,6 +3750,7 @@
mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
}
mApplyFlags = parcel.readInt();
+ mProviderInstanceId = parcel.readLong();
}
private void readActionsFromParcel(Parcel parcel, int depth) {
@@ -6021,6 +6028,7 @@
mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
}
dest.writeInt(mApplyFlags);
+ dest.writeLong(mProviderInstanceId);
}
private void writeActionsToParcel(Parcel parcel) {
@@ -6711,4 +6719,85 @@
public @IdRes int getViewId() {
return mViewId;
}
+
+ /**
+ * Set the provider instance ID.
+ *
+ * This should only be used by {@link com.android.server.appwidget.AppWidgetService}.
+ * @hide
+ */
+ public void setProviderInstanceId(long id) {
+ mProviderInstanceId = id;
+ }
+
+ /**
+ * Get the provider instance id.
+ *
+ * This should uniquely identifies {@link RemoteViews} coming from a given App Widget
+ * Provider. This changes each time the App Widget provider update the {@link RemoteViews} of
+ * its widget. Returns -1 if the {@link RemoteViews} doesn't come from an App Widget provider.
+ * @hide
+ */
+ public long getProviderInstanceId() {
+ return mProviderInstanceId;
+ }
+
+ /**
+ * Identify the child of this {@link RemoteViews}, or 0 if this is not a child.
+ *
+ * The returned value is always a small integer, currently between 0 and 17.
+ */
+ private int getChildId(@NonNull RemoteViews child) {
+ if (child == this) {
+ return 0;
+ }
+ if (hasSizedRemoteViews()) {
+ for (int i = 0; i < mSizedRemoteViews.size(); i++) {
+ if (mSizedRemoteViews.get(i) == child) {
+ return i + 1;
+ }
+ }
+ }
+ if (hasLandscapeAndPortraitLayouts()) {
+ if (mLandscape == child) {
+ return 1;
+ } else if (mPortrait == child) {
+ return 2;
+ }
+ }
+ // This is not a child of this RemoteViews.
+ return 0;
+ }
+
+ /**
+ * Identify uniquely this RemoteViews, or returns -1 if not possible.
+ *
+ * @param parent If the {@link RemoteViews} is not a root {@link RemoteViews}, this should be
+ * the parent that contains it.
+ *
+ * @hide
+ */
+ public long computeUniqueId(@Nullable RemoteViews parent) {
+ if (mIsRoot) {
+ long viewId = getProviderInstanceId();
+ if (viewId != -1) {
+ viewId <<= 8;
+ }
+ return viewId;
+ }
+ if (parent == null) {
+ return -1;
+ }
+ long viewId = parent.getProviderInstanceId();
+ if (viewId == -1) {
+ return -1;
+ }
+ int childId = parent.getChildId(this);
+ if (childId == -1) {
+ return -1;
+ }
+ viewId <<= 8;
+ viewId |= childId;
+ return viewId;
+ }
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 9749a68..6b33428 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -86,8 +86,8 @@
// Default height for the default loading view, in case we cannot get inflate the first view
private static final int DEFAULT_LOADING_VIEW_HEIGHT = 50;
- // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
- // structures;
+ // We cache the FixedSizeRemoteViewsCaches across orientation and re-inflation due to color
+ // palette changes. These are the related data structures:
private static final HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>
sCachedRemoteViewsCaches = new HashMap<>();
private static final HashMap<RemoteViewsCacheKey, Runnable>
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6755be1..f76cccb 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -671,6 +671,8 @@
char extraOptsBuf[PROPERTY_VALUE_MAX];
char voldDecryptBuf[PROPERTY_VALUE_MAX];
char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
+ char perfettoJavaHeapStackOptBuf[
+ sizeof("-XX:PerfettoJavaHeapStackProf=") + PROPERTY_VALUE_MAX];
enum {
kEMDefault,
kEMIntPortable,
@@ -785,6 +787,10 @@
parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=",
"true");
+ // Enable PerfettoJavaHeapStackProf in the zygote
+ parseRuntimeOption("dalvik.vm.perfetto_javaheap", perfettoJavaHeapStackOptBuf,
+ "-XX:PerfettoJavaHeapStackProf=", "true");
+
if (primary_zygote) {
addOption("-Xprimaryzygote");
}
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 5acbd98..6971301 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -578,6 +578,15 @@
event->transform(matrix);
}
+static void android_view_MotionEvent_nativeApplyTransform(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jobject matrixObj) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+
+ std::array<float, 9> matrix;
+ AMatrix_getContents(env, matrixObj, matrix.data());
+ event->applyTransform(matrix);
+}
+
// ----------------- @CriticalNative ------------------------------
static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sourceNativePtr,
@@ -790,6 +799,8 @@
{"nativeGetAxisValue", "(JIII)F", (void*)android_view_MotionEvent_nativeGetAxisValue},
{"nativeTransform", "(JLandroid/graphics/Matrix;)V",
(void*)android_view_MotionEvent_nativeTransform},
+ {"nativeApplyTransform", "(JLandroid/graphics/Matrix;)V",
+ (void*)android_view_MotionEvent_nativeApplyTransform},
// --------------- @CriticalNative ------------------
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4b828ba..4e7dd91 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -410,6 +410,8 @@
<protected-broadcast android:name="android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED" />
<protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
<protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
+ <!-- This broadcast is no longer sent in S but it should stay protected to avoid third party
+ apps broadcasting this and confusing old system apps that may not have been updated. -->
<protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
<protected-broadcast
android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6be6167..ade8516 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -936,7 +936,7 @@
<dimen name="system_app_widget_background_radius">16dp</dimen>
<!-- System-provided radius for inner views on app widgets. The resolved value of this resource may change at runtime. -->
<dimen name="system_app_widget_inner_radius">8dp</dimen>
- <!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_internal_padding">16dp</dimen>
+ <!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. @removed -->
+ <dimen name="__removed_system_app_widget_internal_padding">16dp</dimen>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 03701c3..500a9da 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3184,7 +3184,7 @@
<!-- System-provided dimensions for app widgets. -->
<public name="system_app_widget_background_radius" />
<public name="system_app_widget_inner_radius" />
- <public name="system_app_widget_internal_padding" />
+ <public name="__removed_system_app_widget_internal_padding" />
</staging-public-group>
<staging-public-group type="bool" first-id="0x01110007">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e86d2ce..03bb168 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3390,6 +3390,23 @@
<!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when the bulk of the upgrade work is done. -->
<string name="android_upgrading_complete">Finishing boot.</string>
+ <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
+ is pressed during fingerprint enrollment. -->
+ <string name="fp_enrollment_powerbutton_intent_title">Turn off screen?</string>
+
+ <!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
+ button is pressed during fingerprint enrollment. -->
+ <string name="fp_enrollment_powerbutton_intent_message">While setting up your fingerprint, you
+ pressed the Power button.\n\nThis usually turns off your screen.</string>
+
+ <!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
+ power button is pressed during fingerprint enrollment. -->
+ <string name="fp_enrollment_powerbutton_intent_positive_button">Turn off</string>
+
+ <!-- [CHAR LIMIT=20] Negative button of dialog shown to confirm device going to sleep if the
+ power button is pressed during fingerprint enrollment. -->
+ <string name="fp_enrollment_powerbutton_intent_negative_button">Cancel</string>
+
<!-- Notification text to tell the user that a heavy-weight application is running. -->
<string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3a22efc..b8f82b4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1814,6 +1814,10 @@
<java-symbol type="string" name="bugreport_status" />
<java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
+ <java-symbol type="string" name="fp_enrollment_powerbutton_intent_title" />
+ <java-symbol type="string" name="fp_enrollment_powerbutton_intent_message" />
+ <java-symbol type="string" name="fp_enrollment_powerbutton_intent_positive_button" />
+ <java-symbol type="string" name="fp_enrollment_powerbutton_intent_negative_button" />
<java-symbol type="string" name="global_actions" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_action_power_options" />
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index e9e58c6..a5184f2 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.os.SystemProperties;
import android.util.Pools.SynchronizedPool;
@@ -227,11 +228,11 @@
public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
- RuntimeShader shader) {
+ @ColorInt int color, RuntimeShader shader) {
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
radius.getNativeContainer(), paint.getNativeContainer(),
progress.getNativeContainer(), turbulencePhase.getNativeContainer(),
- shader.getNativeShaderBuilder());
+ color, shader.getNativeShaderBuilder());
}
/**
@@ -292,7 +293,7 @@
long propCy, long propRadius, long propPaint);
@CriticalNative
private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
- long propPaint, long propProgress, long turbulencePhase, long runtimeEffect);
+ long propPaint, long propProgress, long turbulencePhase, int color, long runtimeEffect);
@CriticalNative
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
long propRight, long propBottom, long propRx, long propRy, long propPaint);
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index cff7dcc..a03931b 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -369,7 +369,9 @@
final PackageManager pm = context.getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(
- resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ resPackage,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.GET_SHARED_LIBRARY_FILES);
if (ai != null) {
mObj1 = pm.getResourcesForApplication(ai);
} else {
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 60f73b5..ee867dd 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas;
@@ -211,6 +212,7 @@
CanvasProperty.createFloat(mProperties.getNoisePhase()),
CanvasProperty.createPaint(mProperties.getPaint()),
CanvasProperty.createFloat(mProperties.getProgress()),
+ mProperties.getColor(),
mProperties.getShader());
}
return mCanvasProperties;
@@ -250,11 +252,12 @@
private final FloatType mNoisePhase;
private final PaintType mPaint;
private final RippleShader mShader;
+ private final @ColorInt int mColor;
private FloatType mX;
private FloatType mY;
AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase,
- PaintType paint, FloatType progress, RippleShader shader) {
+ PaintType paint, FloatType progress, @ColorInt int color, RippleShader shader) {
mY = y;
mX = x;
mMaxRadius = maxRadius;
@@ -262,6 +265,7 @@
mPaint = paint;
mShader = shader;
mProgress = progress;
+ mColor = color;
}
FloatType getProgress() {
@@ -296,5 +300,9 @@
FloatType getNoisePhase() {
return mNoisePhase;
}
+
+ @ColorInt int getColor() {
+ return mColor;
+ }
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 24d7780..d00916b49 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -901,7 +901,7 @@
yProp = p.getY();
}
can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
- p.getProgress(), p.getNoisePhase(), p.getShader());
+ p.getProgress(), p.getNoisePhase(), p.getColor(), p.getShader());
} else {
RippleAnimationSession.AnimationProperties<Float, Paint> p =
s.getProperties();
@@ -974,7 +974,7 @@
shader.setRadius(radius);
shader.setProgress(.0f);
properties = new RippleAnimationSession.AnimationProperties<>(
- cx, cy, radius, 0f, p, 0f, shader);
+ cx, cy, radius, 0f, p, 0f, color, shader);
if (mMaskShader == null) {
shader.setShader(null);
} else {
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 66d842e..4da2a28 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -260,6 +260,11 @@
} catch (SecurityException e) {
throw e;
} catch (Exception e) {
+ // If a DeviceIdAttestationException was previously wrapped with some other type,
+ // let's throw the original exception instead of wrapping it yet again.
+ if (e.getCause() instanceof DeviceIdAttestationException) {
+ throw (DeviceIdAttestationException) e.getCause();
+ }
throw new DeviceIdAttestationException("Unable to perform attestation", e);
}
}
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index 9d03ce5..d0d24a8 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -31,7 +31,7 @@
namespace android::uirenderer {
-static SkColor makeLight(SkColor color) {
+SkColor makeLight(SkColor color) {
Lab lab = sRGBToLab(color);
float invertedL = std::min(110 - lab.L, 100.0f);
if (invertedL > lab.L) {
@@ -42,7 +42,7 @@
}
}
-static SkColor makeDark(SkColor color) {
+SkColor makeDark(SkColor color) {
Lab lab = sRGBToLab(color);
float invertedL = std::min(110 - lab.L, 100.0f);
if (invertedL < lab.L) {
@@ -53,7 +53,7 @@
}
}
-static SkColor transformColor(ColorTransform transform, SkColor color) {
+SkColor transformColor(ColorTransform transform, SkColor color) {
switch (transform) {
case ColorTransform::Light:
return makeLight(color);
@@ -64,6 +64,17 @@
}
}
+SkColor transformColorInverse(ColorTransform transform, SkColor color) {
+ switch (transform) {
+ case ColorTransform::Dark:
+ return makeLight(color);
+ case ColorTransform::Light:
+ return makeDark(color);
+ default:
+ return color;
+ }
+}
+
static void applyColorTransform(ColorTransform transform, SkPaint& paint) {
if (transform == ColorTransform::None) return;
diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h
index e723d64..c46a2d3 100644
--- a/libs/hwui/CanvasTransform.h
+++ b/libs/hwui/CanvasTransform.h
@@ -42,4 +42,7 @@
bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette);
+SkColor transformColor(ColorTransform transform, SkColor color);
+SkColor transformColorInverse(ColorTransform transform, SkColor color);
+
} // namespace android::uirenderer;
\ No newline at end of file
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 1b1be43..fb3e21f 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -49,4 +49,5 @@
X(DrawAtlas)
X(DrawShadowRec)
X(DrawVectorDrawable)
+X(DrawRippleDrawable)
X(DrawWebView)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 170f731..442ae0f 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -36,6 +36,7 @@
#include "SkTextBlob.h"
#include "SkVertices.h"
#include "VectorDrawable.h"
+#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
namespace android {
@@ -497,6 +498,18 @@
SkPaint paint;
BitmapPalette palette;
};
+
+struct DrawRippleDrawable final : Op {
+ static const auto kType = Type::DrawRippleDrawable;
+ DrawRippleDrawable(const skiapipeline::RippleDrawableParams& params) : mParams(params) {}
+
+ void draw(SkCanvas* canvas, const SkMatrix&) const {
+ skiapipeline::AnimatedRippleDrawable::draw(canvas, mParams);
+ }
+
+ skiapipeline::RippleDrawableParams mParams;
+};
+
struct DrawWebView final : Op {
static const auto kType = Type::DrawWebView;
DrawWebView(skiapipeline::FunctorDrawable* drawable) : drawable(sk_ref_sp(drawable)) {}
@@ -721,6 +734,10 @@
mHasText = true;
}
+void DisplayListData::drawRippleDrawable(const skiapipeline::RippleDrawableParams& params) {
+ this->push<DrawRippleDrawable>(0, params);
+}
+
void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4],
const SkPoint texs[4], SkBlendMode bmode, const SkPaint& paint) {
this->push<DrawPatch>(0, points, colors, texs, bmode, paint);
@@ -851,6 +868,16 @@
};
}
+template <>
+constexpr color_transform_fn colorTransformForOp<DrawRippleDrawable>() {
+ return [](const void* opRaw, ColorTransform transform) {
+ const DrawRippleDrawable* op = reinterpret_cast<const DrawRippleDrawable*>(opRaw);
+ // Ripple drawable needs to contrast against the background, so we need the inverse color.
+ SkColor color = transformColorInverse(transform, op->mParams.color);
+ const_cast<DrawRippleDrawable*>(op)->mParams.color = color;
+ };
+}
+
#define X(T) colorTransformForOp<T>(),
static const color_transform_fn color_transform_fns[] = {
#include "DisplayListOps.in"
@@ -985,6 +1012,10 @@
fDL->drawTextBlob(blob, x, y, paint);
}
+void RecordingCanvas::drawRippleDrawable(const skiapipeline::RippleDrawableParams& params) {
+ fDL->drawRippleDrawable(params);
+}
+
void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
const SkSamplingOptions& sampling, const SkPaint* paint,
BitmapPalette palette) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index a6a7b12..4fae6a1 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -29,6 +29,9 @@
#include "SkPath.h"
#include "SkRect.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+
+#include <SkRuntimeEffect.h>
#include <vector>
namespace android {
@@ -125,6 +128,7 @@
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*);
+ void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
void drawVectorDrawable(VectorDrawableRoot* tree);
void drawWebView(skiapipeline::FunctorDrawable*);
@@ -184,6 +188,7 @@
void drawImage(const sk_sp<SkImage>&, SkScalar left, SkScalar top, const SkSamplingOptions&,
const SkPaint* paint, BitmapPalette pallete);
+ void drawRippleDrawable(const skiapipeline::RippleDrawableParams& params);
void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
const SkSamplingOptions&, const SkPaint*, SrcRectConstraint, BitmapPalette);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 3056e97..d032e2b 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -815,17 +815,8 @@
mCanvas->drawDrawable(drawable.get());
}
-void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder) {
- sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
- new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
- turbulencePhase, effectBuilder));
- mCanvas->drawDrawable(drawable.get());
+void SkiaCanvas::drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) {
+ uirenderer::skiapipeline::AnimatedRippleDrawable::draw(mCanvas, params);
}
void SkiaCanvas::drawPicture(const SkPicture& picture) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 995f00c..438a40c 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -25,6 +25,7 @@
#include "hwui/Paint.h"
#include <SkCanvas.h>
+#include "pipeline/skia/AnimatedDrawables.h"
#include "src/core/SkArenaAlloc.h"
#include <cassert>
@@ -148,13 +149,7 @@
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override;
- virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder) override;
+ virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index b55ef9d..6e18e49 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -43,7 +43,7 @@
DrawRoundRectProperty,
DrawDoubleRoundRect,
DrawCircleProperty,
- DrawRippleProperty,
+ DrawRippleDrawable,
DrawCircle,
DrawOval,
DrawArc,
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 173f394..fdc97a4 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -145,73 +145,13 @@
ASSERT_DRAWABLE()
};
-template<>
-struct CanvasOp<CanvasOpType::DrawRippleProperty> {
- sp<uirenderer::CanvasPropertyPrimitive> x;
- sp<uirenderer::CanvasPropertyPrimitive> y;
- sp<uirenderer::CanvasPropertyPrimitive> radius;
- sp<uirenderer::CanvasPropertyPaint> paint;
- sp<uirenderer::CanvasPropertyPrimitive> progress;
- sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
- sk_sp<SkRuntimeEffect> effect;
-
- const float PI = 3.1415926535897932384626;
- const float PI_ROTATE_RIGHT = PI * 0.0078125;
- const float PI_ROTATE_LEFT = PI * -0.0078125;
- const float SCALE = 1.5;
- const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
- const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
- const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
- const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
- const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
- const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
+template <>
+struct CanvasOp<CanvasOpType::DrawRippleDrawable> {
+ skiapipeline::RippleDrawableParams params;
void draw(SkCanvas* canvas) const {
- SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
-
- setUniform2f(runtimeEffectBuilder, "in_origin", x->value, y->value);
- setUniform(runtimeEffectBuilder, "in_radius", radius);
- setUniform(runtimeEffectBuilder, "in_progress", progress);
- setUniform(runtimeEffectBuilder, "in_turbulencePhase", turbulencePhase);
-
- //
- // Keep in sync with:
- // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
- //
- const float turbulence = turbulencePhase->value;
- setUniform2f(runtimeEffectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulence * CIRCLE_X_1),
- SCALE * 0.5 + (turbulence * CIRCLE_Y_1));
- setUniform2f(runtimeEffectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulence * CIRCLE_X_2),
- SCALE * 0.2 + (turbulence * CIRCLE_Y_2));
- setUniform2f(runtimeEffectBuilder, "in_tCircle3", SCALE + (turbulence * CIRCLE_X_3),
- SCALE + (turbulence * CIRCLE_Y_3));
- const float rotation1 = turbulence * PI_ROTATE_RIGHT + 1.7 * PI;
- setUniform2f(runtimeEffectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1));
- const float rotation2 = turbulence * PI_ROTATE_LEFT + 2 * PI;
- setUniform2f(runtimeEffectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2));
- const float rotation3 = turbulence * PI_ROTATE_RIGHT + 2.75 * PI;
- setUniform2f(runtimeEffectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
-
- SkPaint paintMod = paint->value;
- paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
- canvas->drawCircle(x->value, y->value, radius->value, paintMod);
+ skiapipeline::AnimatedRippleDrawable::draw(canvas, params);
}
-
- void setUniform(SkRuntimeShaderBuilder& effect, std::string name,
- sp<uirenderer::CanvasPropertyPrimitive> property) const {
- SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
- if (uniform.fVar != nullptr) {
- uniform = property->value;
- }
- }
-
- void setUniform2f(SkRuntimeShaderBuilder effect, std::string name, float a, float b) const {
- SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str());
- if (uniform.fVar != nullptr) {
- uniform = SkV2{a, b};
- }
- }
-
ASSERT_DRAWABLE()
};
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 837b055..9023613 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -22,6 +22,7 @@
#include <androidfw/ResourceTypes.h>
#include "Properties.h"
+#include "pipeline/skia/AnimatedDrawables.h"
#include "utils/Macros.h"
#include <SkBitmap.h>
@@ -141,13 +142,7 @@
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) = 0;
- virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder) = 0;
+ virtual void drawRipple(const uirenderer::skiapipeline::RippleDrawableParams& params) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index eb5a88a..f060bb3 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -144,7 +144,7 @@
static void android_view_DisplayListCanvas_drawRippleProps(
CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr,
jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr,
- jlong builderPtr) {
+ jint color, jlong builderPtr) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
@@ -155,8 +155,12 @@
CanvasPropertyPrimitive* progressProp =
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr);
- canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, turbulencePhaseProp,
- *builder);
+
+ const uirenderer::skiapipeline::RippleDrawableParams params =
+ uirenderer::skiapipeline::RippleDrawableParams{
+ xProp, yProp, radiusProp, progressProp, turbulencePhaseProp,
+ (SkColor)color, paintProp, *builder};
+ canvas->drawRipple(params);
}
static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
@@ -186,7 +190,7 @@
{"nDrawCircle", "(JJJJJ)V", (void*)android_view_DisplayListCanvas_drawCircleProps},
{"nDrawRoundRect", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRoundRectProps},
{"nDrawWebViewFunctor", "(JI)V", (void*)android_view_DisplayListCanvas_drawWebViewFunctor},
- {"nDrawRipple", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
+ {"nDrawRipple", "(JJJJJJJIJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps},
};
int register_android_view_DisplayListCanvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 7d65be1..10889e7 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -22,6 +22,7 @@
#include <math.h>
#include <utils/RefBase.h>
#include "CanvasProperty.h"
+#include "CanvasTransform.h"
namespace android {
namespace uirenderer {
@@ -56,89 +57,80 @@
sp<uirenderer::CanvasPropertyPaint> mPaint;
};
-class AnimatedRipple : public SkDrawable {
-public:
- AnimatedRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder)
- : mX(x)
- , mY(y)
- , mRadius(radius)
- , mPaint(paint)
- , mProgress(progress)
- , mTurbulencePhase(turbulencePhase)
- , mRuntimeEffectBuilder(effectBuilder) {}
+struct RippleDrawableParams {
+ sp<uirenderer::CanvasPropertyPrimitive> x;
+ sp<uirenderer::CanvasPropertyPrimitive> y;
+ sp<uirenderer::CanvasPropertyPrimitive> radius;
+ sp<uirenderer::CanvasPropertyPrimitive> progress;
+ sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
+ SkColor color;
+ sp<uirenderer::CanvasPropertyPaint> paint;
+ SkRuntimeShaderBuilder effectBuilder;
+};
-protected:
- virtual SkRect onGetBounds() override {
- const float x = mX->value;
- const float y = mY->value;
- const float radius = mRadius->value;
- return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
- }
- virtual void onDraw(SkCanvas* canvas) override {
- setUniform2f("in_origin", mX->value, mY->value);
- setUniform("in_radius", mRadius);
- setUniform("in_progress", mProgress);
- setUniform("in_turbulencePhase", mTurbulencePhase);
+class AnimatedRippleDrawable {
+public:
+ static void draw(SkCanvas* canvas, const RippleDrawableParams& params) {
+ auto& effectBuilder = const_cast<SkRuntimeShaderBuilder&>(params.effectBuilder);
+
+ setUniform2f(effectBuilder, "in_origin", params.x->value, params.y->value);
+ setUniform(effectBuilder, "in_radius", params.radius);
+ setUniform(effectBuilder, "in_progress", params.progress);
+ setUniform(effectBuilder, "in_turbulencePhase", params.turbulencePhase);
+
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform("in_color");
+ if (uniform.fVar != nullptr) {
+ uniform = SkV4{SkColorGetR(params.color) / 255.0f, SkColorGetG(params.color) / 255.0f,
+ SkColorGetB(params.color) / 255.0f, SkColorGetA(params.color) / 255.0f};
+ }
+
+ const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
+ const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
+ const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
+ const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
+ const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
+ const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
//
// Keep in sync with:
// frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
//
- const float turbulencePhase = mTurbulencePhase->value;
- setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
+ const float turbulencePhase = params.turbulencePhase->value;
+ setUniform2f(effectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1));
- setUniform2f("in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2),
+ setUniform2f(effectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2),
SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2));
- setUniform2f("in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
+ setUniform2f(effectBuilder, "in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3),
SCALE + (turbulencePhase * CIRCLE_Y_3));
const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI;
- setUniform2f("in_tRotation1", cos(rotation1), sin(rotation1));
+ setUniform2f(effectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1));
const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI;
- setUniform2f("in_tRotation2", cos(rotation2), sin(rotation2));
+ setUniform2f(effectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2));
const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI;
- setUniform2f("in_tRotation3", cos(rotation3), sin(rotation3));
+ setUniform2f(effectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3));
- SkPaint paint = mPaint->value;
- paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
- canvas->drawCircle(mX->value, mY->value, mRadius->value, paint);
+ params.paint->value.setShader(effectBuilder.makeShader(nullptr, false));
+ canvas->drawCircle(params.x->value, params.y->value, params.radius->value,
+ params.paint->value);
}
private:
- sp<uirenderer::CanvasPropertyPrimitive> mX;
- sp<uirenderer::CanvasPropertyPrimitive> mY;
- sp<uirenderer::CanvasPropertyPrimitive> mRadius;
- sp<uirenderer::CanvasPropertyPaint> mPaint;
- sp<uirenderer::CanvasPropertyPrimitive> mProgress;
- sp<uirenderer::CanvasPropertyPrimitive> mTurbulencePhase;
- SkRuntimeShaderBuilder mRuntimeEffectBuilder;
+ static constexpr float PI = 3.1415926535897932384626;
+ static constexpr float PI_ROTATE_RIGHT = PI * 0.0078125;
+ static constexpr float PI_ROTATE_LEFT = PI * -0.0078125;
+ static constexpr float SCALE = 1.5;
- const float PI = 3.1415926535897932384626;
- const float PI_ROTATE_RIGHT = PI * 0.0078125;
- const float PI_ROTATE_LEFT = PI * -0.0078125;
- const float SCALE = 1.5;
- const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55);
- const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55);
- const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45);
- const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45);
- const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35);
- const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35);
-
- virtual void setUniform(std::string name, sp<uirenderer::CanvasPropertyPrimitive> property) {
- SkRuntimeShaderBuilder::BuilderUniform uniform =
- mRuntimeEffectBuilder.uniform(name.c_str());
+ static void setUniform(SkRuntimeShaderBuilder& effectBuilder, std::string name,
+ sp<uirenderer::CanvasPropertyPrimitive> property) {
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
if (uniform.fVar != nullptr) {
uniform = property->value;
}
}
- virtual void setUniform2f(std::string name, float a, float b) {
- SkRuntimeShaderBuilder::BuilderUniform uniform =
- mRuntimeEffectBuilder.uniform(name.c_str());
+ static void setUniform2f(SkRuntimeShaderBuilder& effectBuilder, std::string name, float a,
+ float b) {
+ SkRuntimeShaderBuilder::BuilderUniform uniform = effectBuilder.uniform(name.c_str());
if (uniform.fVar != nullptr) {
uniform = SkV2{a, b};
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 9e73f04..76c4a03 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -109,15 +109,8 @@
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
}
-void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder) {
- drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
- turbulencePhase, effectBuilder));
+void SkiaRecordingCanvas::drawRipple(const skiapipeline::RippleDrawableParams& params) {
+ mRecorder.drawRippleDrawable(params);
}
void SkiaRecordingCanvas::enableZ(bool enableZ) {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 4deb3b9..1445a27 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -20,6 +20,7 @@
#include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h"
#include "SkiaDisplayList.h"
+#include "pipeline/skia/AnimatedDrawables.h"
namespace android {
namespace uirenderer {
@@ -70,13 +71,7 @@
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override;
- virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint,
- uirenderer::CanvasPropertyPrimitive* progress,
- uirenderer::CanvasPropertyPrimitive* turbulencePhase,
- const SkRuntimeShaderBuilder& effectBuilder) override;
+ virtual void drawRipple(const RippleDrawableParams& params) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index a718d46..2cf3456 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -31,6 +31,7 @@
using namespace android;
using namespace android::uirenderer;
+using namespace android::uirenderer::skiapipeline;
using namespace android::uirenderer::test;
// We lazy
@@ -569,6 +570,33 @@
EXPECT_EQ(2, canvas.sumTotalDrawCalls());
}
+TEST(CanvasOp, simpleDrawRipple) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ const char* sksl =
+ "half4 main(float2 coord) {"
+ " return half4(1.);"
+ "}";
+ auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(sksl));
+ auto params = RippleDrawableParams{
+ .x = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(100)),
+ .y = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(200)),
+ .radius = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(50)),
+ .progress = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(0.5)),
+ .turbulencePhase = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(1)),
+ .color = 0xff00ff,
+ .paint = sp<CanvasPropertyPaint>(new CanvasPropertyPaint(SkPaint{})),
+ .effectBuilder = SkRuntimeShaderBuilder(effect)};
+ buffer.push<Op::DrawRippleDrawable>({.params = params});
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawOvalCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
TEST(CanvasOp, immediateRendering) {
auto canvas = std::make_shared<CallCountingCanvas>();
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 480e2ea..4c8a8fa 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -78,6 +78,7 @@
public class MediaRouter {
private static final String TAG = "MediaRouter";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG_RESTORE_ROUTE = true;
static class Static implements DisplayManager.DisplayListener {
final String mPackageName;
@@ -261,8 +262,8 @@
if (audioRoutesChanged) {
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
- if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
- || mSelectedRoute == mBluetoothA2dpRoute) {
+ if (mSelectedRoute == null || mSelectedRoute.isDefault()
+ || mSelectedRoute.isBluetooth()) {
if (forceUseDefaultRoute || mBluetoothA2dpRoute == null) {
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
} else {
@@ -665,12 +666,16 @@
// Skip restoring route if the selected route is not a system audio route,
// MediaRouter is initializing, or mClient was changed.
if (Client.this != mClient || mSelectedRoute == null
- || (mSelectedRoute != mDefaultAudioVideo
- && mSelectedRoute != mBluetoothA2dpRoute)) {
+ || (!mSelectedRoute.isDefault() && !mSelectedRoute.isBluetooth())) {
return;
}
- if (DEBUG) {
- Log.d(TAG, "onRestoreRoute() : route=" + mSelectedRoute);
+ if (DEBUG_RESTORE_ROUTE) {
+ if (mSelectedRoute.isDefault() && mBluetoothA2dpRoute != null) {
+ Log.d(TAG, "onRestoreRoute() : selectedRoute=" + mSelectedRoute
+ + ", a2dpRoute=" + mBluetoothA2dpRoute);
+ } else {
+ Log.d(TAG, "onRestoreRoute() : route=" + mSelectedRoute);
+ }
}
mSelectedRoute.select();
});
@@ -690,9 +695,12 @@
@Override
public void onGlobalA2dpChanged(boolean a2dpOn) {
mHandler.post(() -> {
- if (mSelectedRoute == mDefaultAudioVideo && a2dpOn) {
+ if (mSelectedRoute == null) {
+ return;
+ }
+ if (mSelectedRoute.isDefault() && a2dpOn) {
setSelectedRoute(mBluetoothA2dpRoute, /*explicit=*/false);
- } else if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpOn) {
+ } else if (mSelectedRoute.isBluetooth() && !a2dpOn) {
setSelectedRoute(mDefaultAudioVideo, /*explicit=*/false);
}
});
@@ -1057,8 +1065,8 @@
final RouteInfo oldRoute = sStatic.mSelectedRoute;
final RouteInfo currentSystemRoute = sStatic.isBluetoothA2dpOn()
? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo;
- boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
- || oldRoute == sStatic.mBluetoothA2dpRoute);
+ boolean wasDefaultOrBluetoothRoute = (oldRoute != null)
+ && (oldRoute.isDefault() || oldRoute.isBluetooth());
if (oldRoute == route
&& (!wasDefaultOrBluetoothRoute || route == currentSystemRoute)) {
return;
@@ -1070,14 +1078,17 @@
return;
}
- final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute;
- if (sStatic.isPlaybackActive() && btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0
- && (route == btRoute || route == sStatic.mDefaultAudioVideo)) {
+ if (sStatic.isPlaybackActive() && sStatic.mBluetoothA2dpRoute != null
+ && (types & ROUTE_TYPE_LIVE_AUDIO) != 0
+ && (route.isBluetooth() || route.isDefault())) {
try {
- sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute);
+ sStatic.mAudioService.setBluetoothA2dpOn(route.isBluetooth());
} catch (RemoteException e) {
Log.e(TAG, "Error changing Bluetooth A2DP state", e);
}
+ } else if (DEBUG_RESTORE_ROUTE) {
+ Log.i(TAG, "Skip setBluetoothA2dpOn(): types=" + types + ", isPlaybackActive()="
+ + sStatic.isPlaybackActive() + ", BT route=" + sStatic.mBluetoothA2dpRoute);
}
final WifiDisplay activeDisplay =
@@ -1118,7 +1129,8 @@
static void selectDefaultRouteStatic() {
// TODO: Be smarter about the route types here; this selects for all valid.
- if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute && sStatic.isBluetoothA2dpOn()) {
+ if (sStatic.isBluetoothA2dpOn() && sStatic.mSelectedRoute != null
+ && !sStatic.mSelectedRoute.isBluetooth()) {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
} else {
selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
@@ -1452,8 +1464,7 @@
final RouteInfo selectedRoute = sStatic.mSelectedRoute;
if (selectedRoute == null) return;
- if (selectedRoute == sStatic.mBluetoothA2dpRoute ||
- selectedRoute == sStatic.mDefaultAudioVideo) {
+ if (selectedRoute.isBluetooth() || selectedRoute.isDefault()) {
dispatchRouteVolumeChanged(selectedRoute);
} else if (sStatic.mBluetoothA2dpRoute != null) {
dispatchRouteVolumeChanged(sStatic.mIsBluetoothA2dpOn
@@ -2225,7 +2236,7 @@
/** @hide */
public boolean isBluetooth() {
- return this == sStatic.mBluetoothA2dpRoute;
+ return mDeviceType == RouteInfo.DEVICE_TYPE_BLUETOOTH;
}
/** @hide */
diff --git a/native/android/native_window_jni.cpp b/native/android/native_window_jni.cpp
index 859c550..901b4de 100644
--- a/native/android/native_window_jni.cpp
+++ b/native/android/native_window_jni.cpp
@@ -30,7 +30,7 @@
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) {
sp<ANativeWindow> win = android_view_Surface_getNativeWindow(env, surface);
if (win != NULL) {
- win->incStrong((void*)ANativeWindow_fromSurface);
+ ANativeWindow_acquire(win.get());
}
return win.get();
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 95f180a..0210079 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -23,6 +23,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.StringRes;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -632,6 +633,12 @@
.setPositiveButton(R.string.ok, (dialog, which) -> getActivity().finish())
.create();
}
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ getActivity().setResult(Activity.RESULT_CANCELED);
+ getActivity().finish();
+ }
}
/**
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 49152e4..11f7db7 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -451,10 +451,8 @@
<string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"La tablette va bientôt s\'éteindre (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"L\'appareil va bientôt s\'éteindre (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_charging_duration_only (8085099012811384899) -->
- <skip />
- <!-- no translation found for power_charging_duration (6127154952524919719) -->
- <skip />
+ <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Chargée à 100 %% dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Optimisation pour préserver batterie"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 24b2cb8..edf653f 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -576,8 +576,8 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
- <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
- <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activada"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivada"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
<string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
<string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index c07af12..c312456 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -548,7 +548,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"प्रतिबंधित प्रोफ़ाइल"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"नया उपयोगकर्ता जोड़ें?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"आप और ज़्यादा उपयोगकर्ता बनाकर इस डिवाइस को दूसरे लोगों के साथ शेयर कर सकते हैं. हर उपयोगकर्ता के पास अपनी जगह होती है, जिसमें वह मनपसंद तरीके से ऐप्लिकेशन, वॉलपेपर और दूसरी चीज़ों में बदलाव कर सकते हैं. उपयोगकर्ता वाई-फ़ाई जैसी डिवाइस सेटिंग में भी बदलाव कर सकते हैं, जिसका असर हर किसी पर पड़ेगा.\n\nजब आप कोई नया उपयोगकर्ता जोड़ते हैं तो उन्हें अपनी जगह सेट करनी होगी.\n\nकोई भी उपयोगकर्ता दूसरे सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है. ऐसा भी हो सकता है कि सुलभता सेटिंग और सेवाएं नए उपयोगकर्ता को ट्रांसफ़र न हो पाएं."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं तो उसे अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप अपडेट कर सकता है."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तो उसे अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"उपयोगकर्ता को अभी सेट करें?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"पक्का करें कि व्यक्ति डिवाइस का इस्तेमाल करने और अपनी जगह सेट करने के लिए मौजूद है"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"प्रोफ़ाइल अभी सेट करें?"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index a29462a..798531a 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -565,8 +565,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
- <string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 58cef31..0a052df 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -70,4 +70,17 @@
*/
public static final Interpolator TOUCH_RESPONSE_REVERSE =
new PathInterpolator(0.9f, 0f, 0.7f, 1f);
+
+ /**
+ * Interpolate alpha for notifications background scrim during shade expansion.
+ * @param fraction Shade expansion fraction
+ */
+ public static float getNotificationScrimAlpha(float fraction) {
+ fraction = fraction * 1.2f - 0.2f;
+ if (fraction <= 0) {
+ return 0;
+ } else {
+ return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * Math.pow(1f - fraction, 2f))));
+ }
+ }
}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 9bb2dde..69ce275 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -20,10 +20,13 @@
import android.app.smartspace.SmartspaceAction;
import android.app.smartspace.SmartspaceTarget;
import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.os.Parcelable;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.Nullable;
+
import com.android.systemui.plugins.annotations.ProvidesInterface;
import java.util.List;
@@ -50,6 +53,11 @@
return null;
}
+ /**
+ * As the smartspace view becomes available, allow listeners to receive an event.
+ */
+ default void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) { }
+
/** Updates Smartspace data and propagates it to any listeners. */
void onTargetsAvailable(List<SmartspaceTarget> targets);
@@ -83,6 +91,11 @@
* When on the lockscreen, use the FalsingManager to help detect errant touches
*/
void setFalsingManager(com.android.systemui.plugins.FalsingManager falsingManager);
+
+ /**
+ * Set or clear any Do Not Disturb information.
+ */
+ void setDnd(@Nullable Icon dndIcon, @Nullable String description);
}
/** Interface for launching Intents, which can differ on the lockscreen */
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 1cef44b..7c5459c1 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -80,6 +80,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/notification_shelf_height"
android:layout_below="@id/keyguard_status_area"
- android:paddingStart="@dimen/below_clock_padding_start"
+ android:paddingStart="@dimen/below_clock_padding_start_extra"
/>
</com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 9b8035d..a166b09 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -94,4 +94,5 @@
<!-- additional offset for clock switch area items -->
<dimen name="clock_padding_start">28dp</dimen>
<dimen name="below_clock_padding_start">32dp</dimen>
+ <dimen name="below_clock_padding_start_extra">36dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/drawable/ic_blank.xml b/packages/SystemUI/res/drawable/ic_blank.xml
new file mode 100644
index 0000000..b94088f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_blank.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="16.0">
+ <path/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_sim_card.xml b/packages/SystemUI/res/drawable/ic_qs_sim_card.xml
new file mode 100644
index 0000000..6eda929
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_sim_card.xml
@@ -0,0 +1,47 @@
+<!--
+Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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:attr/colorControlNormal"
+ >
+
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18,2h-8L4,8v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2z M18,4v16H6V8.83L10.83,4L18,4L18,4z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 7 17 H 9 V 19 H 7 V 17 Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 15 17 H 17 V 19 H 15 V 17 Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 7 11 H 9 V 15 H 7 V 11 Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 11 15 H 13 V 19 H 11 V 15 Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 11 11 H 13 V 13 H 11 V 11 Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 15 11 H 17 V 15 H 15 V 11 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index 9f41dbe..99c0ab4b 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -16,6 +16,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/privacy_circle" />
+ <solid android:color="@color/privacy_chip_background" />
<corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/privacy_item_circle_camera.xml b/packages/SystemUI/res/drawable/privacy_item_circle_camera.xml
index 54a66e2..f4ff549 100644
--- a/packages/SystemUI/res/drawable/privacy_item_circle_camera.xml
+++ b/packages/SystemUI/res/drawable/privacy_item_circle_camera.xml
@@ -24,7 +24,7 @@
android:height="@dimen/ongoing_appops_dialog_circle_size"
android:width="@dimen/ongoing_appops_dialog_circle_size"
/>
- <solid android:color="@color/privacy_circle" />
+ <solid android:color="@color/privacy_chip_background" />
</shape>
</item>
<item android:id="@id/icon"
diff --git a/packages/SystemUI/res/drawable/privacy_item_circle_location.xml b/packages/SystemUI/res/drawable/privacy_item_circle_location.xml
index 65f4396..9a201886 100644
--- a/packages/SystemUI/res/drawable/privacy_item_circle_location.xml
+++ b/packages/SystemUI/res/drawable/privacy_item_circle_location.xml
@@ -24,7 +24,7 @@
android:height="@dimen/ongoing_appops_dialog_circle_size"
android:width="@dimen/ongoing_appops_dialog_circle_size"
/>
- <solid android:color="@color/privacy_circle" />
+ <solid android:color="@color/privacy_chip_background" />
</shape>
</item>
<item android:id="@id/icon"
diff --git a/packages/SystemUI/res/drawable/privacy_item_circle_microphone.xml b/packages/SystemUI/res/drawable/privacy_item_circle_microphone.xml
index 1565d2d..a5f2d32 100644
--- a/packages/SystemUI/res/drawable/privacy_item_circle_microphone.xml
+++ b/packages/SystemUI/res/drawable/privacy_item_circle_microphone.xml
@@ -24,7 +24,7 @@
android:height="@dimen/ongoing_appops_dialog_circle_size"
android:width="@dimen/ongoing_appops_dialog_circle_size"
/>
- <solid android:color="@color/privacy_circle" />
+ <solid android:color="@color/privacy_chip_background" />
</shape>
</item>
<item android:id="@id/icon"
diff --git a/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
index 4e9d380..9f81b0d 100644
--- a/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
+++ b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
@@ -18,7 +18,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
- android:color="@color/privacy_circle"/>
+ android:color="@color/privacy_chip_background"/>
<size
android:width="6dp"
android:height="6dp"
diff --git a/packages/SystemUI/res/layout/dock_info_bottom_area_overlay.xml b/packages/SystemUI/res/layout/dock_info_bottom_area_overlay.xml
new file mode 100644
index 0000000..8b70dd7
--- /dev/null
+++ b/packages/SystemUI/res/layout/dock_info_bottom_area_overlay.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- empty stub -->
+<merge />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 52995ea..f4cb3b1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -101,6 +101,8 @@
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
+ <include layout="@layout/dock_info_bottom_area_overlay" />
+
<include
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 8f88950..c473229 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -95,9 +95,6 @@
<!-- Color of background circle of user avatars in quick settings user switcher -->
<color name="qs_user_switcher_avatar_background">#3C4043</color>
- <!-- Colors for privacy dialog. These should be changed to the new palette -->
- <color name="privacy_circle">#81C995</color> <!-- g300 -->
-
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4d9b9e1..08a2e19 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -279,7 +279,7 @@
<color name="screenrecord_status_color">#E94235</color>
- <color name="privacy_circle">#5BB974</color> <!-- g400 -->
+ <color name="privacy_chip_background">#3ddc84</color>
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#CCFFFFFF</color> <!-- 80% -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4da2e33..30add20 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1115,16 +1115,16 @@
<string name="interruption_level_alarms_twoline">Alarms\nonly</string>
<!-- Indication on the keyguard that is shown when the device is wirelessly charging. [CHAR LIMIT=80]-->
- <string name="keyguard_indication_charging_time_wireless"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging wirelessly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time_wireless"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging wirelessly • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=50]-->
- <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=50]-->
- <string name="keyguard_indication_charging_time_fast"><xliff:g id="percentage">%2$s</xliff:g> • Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time_fast"><xliff:g id="percentage">%2$s</xliff:g> • Charging rapidly • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=50]-->
- <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+ <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Related to user switcher --><skip/>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 114472b..277b2e3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -75,4 +75,10 @@
* Sent when the split screen is resized
*/
void onSplitScreenSecondaryBoundsChanged(in Rect bounds, in Rect insets) = 17;
+
+ /**
+ * Sent IME status changes
+ */
+ void onImeWindowStatusChanged(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) = 18;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
index 356e0ca..4394ecb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
@@ -49,7 +49,7 @@
private final TraceBuffer<P, S, T> mBuffer;
private final File mTraceFile;
private final ProtoTraceParams<P, S, T, R> mParams;
- private final Choreographer mChoreographer;
+ private Choreographer mChoreographer;
private final Queue<T> mPool = new LinkedList<>();
private final ArrayList<ProtoTraceable<R>> mTraceables = new ArrayList<>();
private final ArrayList<ProtoTraceable<R>> mTmpTraceables = new ArrayList<>();
@@ -94,7 +94,6 @@
}
});
mTraceFile = params.getTraceFile();
- mChoreographer = Choreographer.getMainThreadInstance();
}
public void start() {
@@ -140,6 +139,9 @@
}
// Schedule an update on the next frame
+ if (mChoreographer == null) {
+ mChoreographer = Choreographer.getMainThreadInstance();
+ }
mChoreographer.postFrameCallback(this);
mFrameScheduled = true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index e92cae4..dfe035d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -45,7 +45,6 @@
import com.android.keyguard.clock.ClockManager;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
@@ -69,6 +68,7 @@
import com.android.systemui.util.settings.SecureSettings;
import java.util.Locale;
+import java.util.Optional;
import java.util.TimeZone;
import java.util.concurrent.Executor;
@@ -89,7 +89,6 @@
private final Executor mUiExecutor;
private final BatteryController mBatteryController;
private final FeatureFlags mFeatureFlags;
- private final SystemUIFactory mSystemUIFactory;
/**
* Clock for both small and large sizes
@@ -152,6 +151,7 @@
// If set, will replace keyguard_status_area
private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
+ private Optional<BcSmartspaceDataPlugin> mSmartspacePlugin;
@Inject
public KeyguardClockSwitchController(
@@ -165,14 +165,14 @@
@Main Executor uiExecutor,
BatteryController batteryController,
ConfigurationController configurationController,
- SystemUIFactory systemUIFactory,
ActivityStarter activityStarter,
FalsingManager falsingManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController bypassController,
@Main Handler handler,
UserTracker userTracker,
- SecureSettings secureSettings) {
+ SecureSettings secureSettings,
+ Optional<BcSmartspaceDataPlugin> smartspacePlugin) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -184,7 +184,6 @@
mUiExecutor = uiExecutor;
mBatteryController = batteryController;
mConfigurationController = configurationController;
- mSystemUIFactory = systemUIFactory;
mActivityStarter = activityStarter;
mFalsingManager = falsingManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -192,6 +191,7 @@
mHandler = handler;
mUserTracker = userTracker;
mSecureSettings = secureSettings;
+ mSmartspacePlugin = smartspacePlugin;
}
/**
@@ -237,8 +237,8 @@
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
- BcSmartspaceDataPlugin smartspaceDataPlugin = mSystemUIFactory.getSmartspaceDataProvider();
- if (mFeatureFlags.isSmartspaceEnabled() && smartspaceDataPlugin != null) {
+ if (mFeatureFlags.isSmartspaceEnabled() && mSmartspacePlugin.isPresent()) {
+ BcSmartspaceDataPlugin smartspaceDataPlugin = mSmartspacePlugin.get();
View ksa = mView.findViewById(R.id.keyguard_status_area);
int ksaIndex = mView.indexOfChild(ksa);
ksa.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index af064e1..cc167b9 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -29,7 +29,6 @@
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
-import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
import com.android.wm.shell.transition.Transitions;
@@ -210,8 +209,4 @@
AssetManager am, String modelName) {
return new BackGestureTfClassifierProvider();
}
-
- public BcSmartspaceDataPlugin getSmartspaceDataProvider() {
- return null;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 126724c..7fa48d4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
@@ -151,6 +152,9 @@
abstract HeadsUpManager optionalHeadsUpManager();
@BindsOptionalOf
+ abstract BcSmartspaceDataPlugin optionalBcSmartspaceDataPlugin();
+
+ @BindsOptionalOf
abstract Recents optionalRecents();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 2450367..7a7198fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -115,6 +115,7 @@
private var needsReordering: Boolean = false
private var keysNeedRemoval = mutableSetOf<String>()
private var bgColor = getBackgroundColor()
+ private var shouldScrollToActivePlayer: Boolean = false
private var isRtl: Boolean = false
set(value) {
if (value != field) {
@@ -271,6 +272,15 @@
}
}
mediaCarouselScrollHandler.onPlayersChanged()
+
+ // Automatically scroll to the active player if needed
+ if (shouldScrollToActivePlayer) {
+ shouldScrollToActivePlayer = false
+ val activeMediaIndex = MediaPlayerData.getActiveMediaIndex()
+ if (activeMediaIndex != -1) {
+ mediaCarouselScrollHandler.scrollToActivePlayer(activeMediaIndex)
+ }
+ }
}
private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) {
@@ -322,8 +332,8 @@
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
- newRecs.bindRecommendation(data, bgColor)
- MediaPlayerData.addMediaPlayer(key, newRecs)
+ newRecs.bindRecommendation(data, bgColor, { v -> shouldScrollToActivePlayer = true })
+ MediaPlayerData.addMediaRecommendation(key, newRecs)
updatePlayerToState(newRecs, noAnimation = true)
reorderAllPlayers()
updatePageIndicator()
@@ -593,7 +603,7 @@
@VisibleForTesting
internal object MediaPlayerData {
private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
- emptyList(), emptyList(), "INVALID", null, null, null, true, null)
+ emptyList(), emptyList(), "INVALID", null, null, null, false, null)
private data class MediaSortKey(
// Is Smartspace media recommendation. When the Smartspace media is present, it should
@@ -620,7 +630,7 @@
mediaPlayers.put(sortKey, player)
}
- fun addMediaPlayer(key: String, player: MediaControlPanel) {
+ fun addMediaRecommendation(key: String, player: MediaControlPanel) {
removeMediaPlayer(key)
val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
mediaData.put(key, sortKey)
@@ -643,6 +653,16 @@
fun players() = mediaPlayers.values
+ /** Returns the index of the first non-timeout media. */
+ fun getActiveMediaIndex(): Int {
+ mediaPlayers.entries.forEachIndexed { index, e ->
+ if (e.key.data.active) {
+ return index
+ }
+ }
+ return -1
+ }
+
@VisibleForTesting
fun clear() {
mediaData.clear()
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index f0b78dd..6358004 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -38,6 +38,7 @@
private const val FLING_SLOP = 1000000
private const val DISMISS_DELAY = 100L
+private const val SCROLL_DELAY = 100L
private const val RUBBERBAND_FACTOR = 0.2f
private const val SETTINGS_BUTTON_TRANSLATION_FRACTION = 0.3f
@@ -100,10 +101,11 @@
private lateinit var settingsButton: View
/**
- * What's the currently active player index?
+ * What's the currently visible player index?
*/
- var activeMediaIndex: Int = 0
+ var visibleMediaIndex: Int = 0
private set
+
/**
* How much are we scrolled into the current media?
*/
@@ -129,7 +131,7 @@
field = value
// The player width has changed, let's update the scroll position to make sure
// it's still at the same place
- var newRelativeScroll = activeMediaIndex * playerWidthPlusPadding
+ var newRelativeScroll = visibleMediaIndex * playerWidthPlusPadding
if (scrollIntoCurrentMedia > playerWidthPlusPadding) {
newRelativeScroll += playerWidthPlusPadding -
(scrollIntoCurrentMedia - playerWidthPlusPadding)
@@ -457,12 +459,12 @@
val wasScrolledIn = scrollIntoCurrentMedia != 0
scrollIntoCurrentMedia = scrollInAmount
val nowScrolledIn = scrollIntoCurrentMedia != 0
- if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
- activeMediaIndex = newIndex
+ if (newIndex != visibleMediaIndex || wasScrolledIn != nowScrolledIn) {
+ visibleMediaIndex = newIndex
closeGuts()
updatePlayerVisibilities()
}
- val relativeLocation = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
+ val relativeLocation = visibleMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
scrollInAmount.toFloat() / playerWidthPlusPadding else 0f
// Fix the location, because PageIndicator does not handle RTL internally
val location = if (isRtl) {
@@ -500,7 +502,7 @@
val scrolledIn = scrollIntoCurrentMedia != 0
for (i in 0 until mediaContent.childCount) {
val view = mediaContent.getChildAt(i)
- val visible = (i == activeMediaIndex) || ((i == (activeMediaIndex + 1)) && scrolledIn)
+ val visible = (i == visibleMediaIndex) || ((i == (visibleMediaIndex + 1)) && scrolledIn)
view.visibility = if (visible) View.VISIBLE else View.INVISIBLE
}
}
@@ -511,12 +513,12 @@
*/
fun onPrePlayerRemoved(removed: MediaControlPanel) {
val removedIndex = mediaContent.indexOfChild(removed.playerViewHolder?.player)
- // If the removed index is less than the activeMediaIndex, then we need to decrement it.
+ // If the removed index is less than the visibleMediaIndex, then we need to decrement it.
// RTL has no effect on this, because indices are always relative (start-to-end).
// Update the index 'manually' since we won't always get a call to onMediaScrollingChanged
- val beforeActive = removedIndex <= activeMediaIndex
+ val beforeActive = removedIndex <= visibleMediaIndex
if (beforeActive) {
- activeMediaIndex = Math.max(0, activeMediaIndex - 1)
+ visibleMediaIndex = Math.max(0, visibleMediaIndex - 1)
}
// If the removed media item is "left of" the active one (in an absolute sense), we need to
// scroll the view to keep that player in view. This is because scroll position is always
@@ -545,6 +547,17 @@
scrollView.relativeScrollX = 0
}
+ fun scrollToActivePlayer(activePlayerIndex: Int) {
+ var destIndex = activePlayerIndex
+ destIndex = Math.min(mediaContent.getChildCount() - 1, destIndex)
+ val view = mediaContent.getChildAt(destIndex)
+ // We need to post this to wait for the active player becomes visible.
+ mainExecutor.executeDelayed({
+ visibleMediaIndex = activePlayerIndex
+ scrollView.smoothScrollTo(view.left, scrollView.scrollY)
+ }, SCROLL_DELAY)
+ }
+
companion object {
private val CONTENT_TRANSLATION = object : FloatPropertyCompat<MediaCarouselScrollHandler>(
"contentTranslation") {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 1e9cc8c..647e8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -462,7 +462,8 @@
/** Bind this recommendation view based on the data given. */
public void bindRecommendation(
@NonNull SmartspaceTarget target,
- @NonNull int backgroundColor) {
+ @NonNull int backgroundColor,
+ @Nullable View.OnClickListener callback) {
if (mRecommendationViewHolder == null) {
return;
}
@@ -526,7 +527,7 @@
setSmartspaceRecItemOnClickListener(
mediaCoverImageView,
recommendation,
- null);
+ callback);
if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
setVisibleAndAlpha(collapsedSet,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 56375ad..4e41d75 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -101,6 +101,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
+import android.view.inputmethod.InputMethodManager;
import androidx.annotation.VisibleForTesting;
@@ -1175,6 +1176,9 @@
accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
updateAccessibilityServicesState(mAccessibilityManager);
+ ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
+ imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
+
updateScreenPinningGestures();
}
@@ -1274,6 +1278,11 @@
mCommandQueue.toggleRecentApps();
}
+ private void onImeSwitcherClick(View v) {
+ mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
+ true /* showAuxiliarySubtypes */, mDisplayId);
+ };
+
private boolean onLongPressBackHome(View v) {
return onLongPressNavigationButtons(v, R.id.back, R.id.home);
}
@@ -1282,7 +1291,6 @@
return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
}
-
/**
* This handles long-press of both back and recents/home. Back is the common button with
* combination of recents if it is visible or home if recents is invisible.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 3544f60..9c3cb2e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -113,6 +113,7 @@
private final Handler mHandler;
private final DisplayManager mDisplayManager;
private final NavigationBarOverlayController mNavBarOverlayController;
+ private final TaskbarDelegate mTaskbarDelegate;
private int mNavMode;
private boolean mIsTablet;
@@ -182,6 +183,7 @@
mNavBarOverlayController = navBarOverlayController;
mNavMode = mNavigationModeController.addListener(this);
mNavigationModeController.addListener(this);
+ mTaskbarDelegate = new TaskbarDelegate(mOverviewProxyService);
}
@Override
@@ -190,17 +192,7 @@
mIsTablet = isTablet(newConfig);
boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
// If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
- if (isThreeButtonTaskbarFlagEnabled() &&
- largeScreenChanged && mNavMode == NAV_BAR_MODE_3BUTTON) {
- if (!mIsTablet) {
- // Folded state, show 3 button nav bar
- createNavigationBar(mContext.getDisplay(), null, null);
- } else {
- // Unfolded state, hide 3 button nav bars
- for (int i = 0; i < mNavigationBars.size(); i++) {
- removeNavigationBar(mNavigationBars.keyAt(i));
- }
- }
+ if (largeScreenChanged && updateNavbarForTaskbar()) {
return;
}
@@ -217,18 +209,15 @@
@Override
public void onNavigationModeChanged(int mode) {
+ if (mNavMode == mode) {
+ return;
+ }
final int oldMode = mNavMode;
mNavMode = mode;
mHandler.post(() -> {
// create/destroy nav bar based on nav mode only in unfolded state
- if (isThreeButtonTaskbarFlagEnabled() && oldMode != mNavMode && mIsTablet) {
- if (oldMode == NAV_BAR_MODE_3BUTTON &&
- mNavigationBars.get(mContext.getDisplayId()) == null) {
- // We remove navbar for 3 button unfolded, add it back in
- createNavigationBar(mContext.getDisplay(), null, null);
- } else if (mNavMode == NAV_BAR_MODE_3BUTTON) {
- removeNavigationBar(mContext.getDisplayId());
- }
+ if (oldMode != mNavMode) {
+ updateNavbarForTaskbar();
}
for (int i = 0; i < mNavigationBars.size(); i++) {
NavigationBar navBar = mNavigationBars.valueAt(i);
@@ -243,6 +232,27 @@
});
}
+ /**
+ * @return {@code true} if navbar was added/removed, false otherwise
+ */
+ public boolean updateNavbarForTaskbar() {
+ if (!isThreeButtonTaskbarFlagEnabled()) {
+ return false;
+ }
+
+ if (mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON) {
+ // Remove navigation bar when taskbar is showing, currently only for 3 button mode
+ removeNavigationBar(mContext.getDisplayId());
+ mCommandQueue.addCallback(mTaskbarDelegate);
+ } else if (mNavigationBars.get(mContext.getDisplayId()) == null) {
+ // Add navigation bar after taskbar goes away
+ createNavigationBar(mContext.getDisplay(), null, null);
+ mCommandQueue.removeCallback(mTaskbarDelegate);
+ }
+
+ return true;
+ }
+
@Override
public void onDisplayRemoved(int displayId) {
removeNavigationBar(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
index 7342f91..4d9175b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
@@ -158,7 +158,6 @@
}
public void onLikelyDefaultLayoutChange() {
-
// Reevaluate new layout
final String newValue = getDefaultLayout();
if (!Objects.equals(mCurrentLayout, newValue)) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 0ed4d86..f82d265d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -166,6 +166,7 @@
private NavigationBarInflaterView mNavigationInflaterView;
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelViewController mPanelView;
+ private RotationContextButton mRotationContextButton;
private FloatingRotationButton mFloatingRotationButton;
private RotationButtonController mRotationButtonController;
private NavigationBarOverlayController mNavBarOverlayController;
@@ -233,14 +234,6 @@
}
}
- private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
- @Override
- public void onClick(View view) {
- mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
- true /* showAuxiliarySubtypes */, getContext().getDisplayId());
- }
- };
-
private final AccessibilityDelegate mQuickStepAccessibilityDelegate =
new AccessibilityDelegate() {
private AccessibilityAction mToggleOverviewAction;
@@ -311,33 +304,26 @@
mIsVertical = false;
mLongClickableAccessibilityButton = false;
mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
- boolean isGesturalMode = isGesturalMode(mNavBarMode);
mSysUiFlagContainer = Dependency.get(SysUiState.class);
// Set up the context group of buttons
mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
mLightContext, R.drawable.ic_ime_switcher_default);
- final RotationContextButton rotateSuggestionButton = new RotationContextButton(
- R.id.rotate_suggestion, mLightContext,
- R.drawable.ic_sysbar_rotate_button_ccw_start_0);
final ContextualButton accessibilityButton =
new ContextualButton(R.id.accessibility_button, mLightContext,
R.drawable.ic_sysbar_accessibility_button);
mContextualButtonGroup.addButton(imeSwitcherButton);
- if (!isGesturalMode) {
- mContextualButtonGroup.addButton(rotateSuggestionButton);
- }
mContextualButtonGroup.addButton(accessibilityButton);
+ mRotationContextButton = new RotationContextButton(R.id.rotate_suggestion,
+ mLightContext, R.drawable.ic_sysbar_rotate_button_ccw_start_0);
+ mFloatingRotationButton = new FloatingRotationButton(context);
+ mRotationButtonController = new RotationButtonController(mLightContext,
+ mLightIconColor, mDarkIconColor);
+ updateRotationButton();
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mFloatingRotationButton = new FloatingRotationButton(context);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
- mRotationButtonController = new RotationButtonController(mLightContext,
- mLightIconColor, mDarkIconColor,
- isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton,
- mRotationButtonListener);
-
mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
mNavBarOverlayController.init(
@@ -357,7 +343,6 @@
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
- mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
mDeadZone = new DeadZone(this);
@@ -555,6 +540,23 @@
}
}
+ /**
+ * Updates the rotation button based on the current navigation mode.
+ */
+ private void updateRotationButton() {
+ if (isGesturalMode(mNavBarMode)) {
+ mContextualButtonGroup.removeButton(R.id.rotate_suggestion);
+ mButtonDispatchers.remove(R.id.rotate_suggestion);
+ mRotationButtonController.setRotationButton(mFloatingRotationButton,
+ mRotationButtonListener);
+ } else if (mContextualButtonGroup.getContextButton(R.id.rotate_suggestion) == null) {
+ mContextualButtonGroup.addButton(mRotationContextButton);
+ mButtonDispatchers.put(R.id.rotate_suggestion, mRotationContextButton);
+ mRotationButtonController.setRotationButton(mRotationContextButton,
+ mRotationButtonListener);
+ }
+ }
+
public KeyButtonDrawable getBackDrawable() {
KeyButtonDrawable drawable = getDrawable(getBackDrawableRes());
orientBackButton(drawable);
@@ -908,6 +910,7 @@
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
+ updateRotationButton();
if (isGesturalMode(mNavBarMode)) {
mRegionSamplingHelper.start(mSamplingBounds);
@@ -932,7 +935,6 @@
mNavigationInflaterView = findViewById(R.id.navigation_inflater);
mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
- getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
updateOrientationViews();
reloadNavIcons();
}
@@ -1027,6 +1029,9 @@
private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace,
boolean useNearestRegion) {
+ if (button == null) {
+ return;
+ }
View view = button.getCurrentView();
if (view == null || !button.isVisible()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index 4bcb019..ddf089b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -66,10 +66,10 @@
private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
private final Context mContext;
- private final RotationButton mRotationButton;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
private final ViewRippler mViewRippler = new ViewRippler();
+ private RotationButton mRotationButton;
private int mLastRotationSuggestion;
private boolean mPendingRotationSuggestion;
@@ -125,20 +125,21 @@
}
RotationButtonController(Context context, @ColorInt int lightIconColor,
- @ColorInt int darkIconColor, RotationButton rotationButton,
- Consumer<Boolean> visibilityChangedCallback) {
+ @ColorInt int darkIconColor) {
mContext = context;
mLightIconColor = lightIconColor;
mDarkIconColor = darkIconColor;
- mRotationButton = rotationButton;
- mRotationButton.setRotationButtonController(this);
mIsNavigationBarShowing = true;
mRotationLockController = Dependency.get(RotationLockController.class);
mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class);
-
- // Register the task stack listener
mTaskStackListener = new TaskStackListenerImpl();
+ }
+
+ void setRotationButton(RotationButton rotationButton,
+ Consumer<Boolean> visibilityChangedCallback) {
+ mRotationButton = rotationButton;
+ mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
new file mode 100644
index 0000000..03147d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigationbar;
+
+import android.os.IBinder;
+
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.statusbar.CommandQueue;
+
+public class TaskbarDelegate implements CommandQueue.Callbacks {
+
+ private final OverviewProxyService mOverviewProxyService;
+
+ public TaskbarDelegate(OverviewProxyService overviewProxyService) {
+ mOverviewProxyService = overviewProxyService;
+ }
+
+ @Override
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ mOverviewProxyService.notifyImeWindowStatus(displayId, token, vis, backDisposition,
+ showImeSwitcher);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java
index 50b638b..2ace303 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java
@@ -41,10 +41,23 @@
* @param button the button added to the group
*/
public void addButton(@NonNull ContextualButton button) {
+ // By default buttons in the context group are not visible until
+ // {@link #setButtonVisibility()) is called to show one of the buttons
+ button.setVisibility(View.INVISIBLE);
button.attachToGroup(this);
mButtonData.add(new ButtonData(button));
}
+ /**
+ * Removes a contextual button from the group.
+ */
+ public void removeButton(@IdRes int buttonResId) {
+ int index = getContextButtonIndex(buttonResId);
+ if (index != INVALID_INDEX) {
+ mButtonData.remove(index);
+ }
+ }
+
public ContextualButton getContextButton(@IdRes int buttonResId) {
int index = getContextButtonIndex(buttonResId);
if (index != INVALID_INDEX) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index a6c6103..29685a4 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -203,7 +203,7 @@
if (DEBUG) {
Log.i(TAG, "Removing any notification stored for tile Id: " + tile.getId());
}
- return tile
+ PeopleSpaceTile.Builder updatedTile = tile
.toBuilder()
// Reset notification content.
.setNotificationKey(null)
@@ -212,8 +212,15 @@
.setNotificationDataUri(null)
.setMessagesCount(0)
// Reset missed calls category.
- .setNotificationCategory(null)
- .build();
+ .setNotificationCategory(null);
+
+ // Only set last interaction to now if we are clearing a notification.
+ if (!TextUtils.isEmpty(tile.getNotificationKey())) {
+ long currentTimeMillis = System.currentTimeMillis();
+ if (DEBUG) Log.d(TAG, "Set last interaction on clear: " + currentTimeMillis);
+ updatedTile.setLastInteractionTimestamp(currentTimeMillis);
+ }
+ return updatedTile.build();
}
/**
@@ -227,10 +234,11 @@
if (DEBUG) Log.d(TAG, "Tile key: " + key.toString() + ". Notification is null");
return removeNotificationFields(tile);
}
- Notification notification = notificationEntry.getSbn().getNotification();
+ StatusBarNotification sbn = notificationEntry.getSbn();
+ Notification notification = sbn.getNotification();
PeopleSpaceTile.Builder updatedTile = tile.toBuilder();
- String uriFromNotification = getContactUri(notificationEntry.getSbn());
+ String uriFromNotification = getContactUri(sbn);
if (appWidgetId.isPresent() && tile.getContactUri() == null && !TextUtils.isEmpty(
uriFromNotification)) {
if (DEBUG) Log.d(TAG, "Add uri from notification to tile: " + uriFromNotification);
@@ -241,7 +249,6 @@
// Update cached tile in-memory.
updatedTile.setContactUri(contactUri);
}
-
boolean isMissedCall = isMissedCall(notification);
List<Notification.MessagingStyle.Message> messages =
getMessagingStyleMessages(notification);
@@ -261,12 +268,13 @@
Uri dataUri = message != null ? message.getDataUri() : null;
if (DEBUG) {
Log.d(TAG, "Tile key: " + key.toString() + ". Notification message has text: "
- + hasMessageText);
+ + hasMessageText + " Has last interaction: " + sbn.getPostTime());
}
CharSequence sender = getSenderIfGroupConversation(notification, message);
return updatedTile
- .setNotificationKey(notificationEntry.getSbn().getKey())
+ .setLastInteractionTimestamp(sbn.getPostTime())
+ .setNotificationKey(sbn.getKey())
.setNotificationCategory(notification.category)
.setNotificationContent(content)
.setNotificationSender(sender)
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 6980d72..06f8a60 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -835,7 +835,7 @@
return null;
} else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
return context.getString(R.string.timestamp, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toHours(),
+ new Measure(durationSinceLastInteraction.toDays(),
MeasureUnit.DAY)));
} else if (durationSinceLastInteraction.toDays() <= DAYS_IN_A_WEEK * 2) {
return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
index 73c43eb..b49533e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/AppWidgetOptionsHelper.java
@@ -16,7 +16,6 @@
package com.android.systemui.people.widget;
-import static com.android.systemui.people.PeopleSpaceUtils.DEBUG;
import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_KEY;
import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING;
import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
@@ -24,38 +23,13 @@
import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID;
import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
-import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.os.Bundle;
-import android.util.Log;
/** Helper class encapsulating AppWidgetOptions for People Tile. */
public class AppWidgetOptionsHelper {
private static final String TAG = "AppWidgetOptionsHelper";
- /** Key to store {@link PeopleSpaceTile} in AppWidgetOptions Bundle. */
- public static final String OPTIONS_PEOPLE_TILE = "options_people_tile";
-
- /** Sets {@link PeopleSpaceTile} in AppWidgetOptions. */
- public static Bundle setPeopleTile(AppWidgetManager appWidgetManager, int appWidgetId,
- PeopleSpaceTile tile) {
- Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
- if (tile == null) {
- if (DEBUG) Log.w(TAG, "Requested to store null tile");
- return options;
- }
- options.putParcelable(OPTIONS_PEOPLE_TILE, tile);
- appWidgetManager.updateAppWidgetOptions(appWidgetId, options);
- return options;
- }
-
- /** Gets {@link PeopleSpaceTile} from AppWidgetOptions. */
- public static PeopleSpaceTile getPeopleTile(AppWidgetManager appWidgetManager,
- int appWidgetId) {
- Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
- return options != null ? options.getParcelable(OPTIONS_PEOPLE_TILE) : null;
- }
-
/** Sets {@link PeopleTileKey} in AppWidgetOptions. */
public static void setPeopleTileKey(AppWidgetManager appWidgetManager, int appWidgetId,
PeopleTileKey key) {
@@ -66,16 +40,6 @@
appWidgetManager.updateAppWidgetOptions(appWidgetId, options);
}
- /** Gets {@link PeopleTileKey} from AppWidgetOptions. */
- public static PeopleTileKey getPeopleTileKey(AppWidgetManager appWidgetManager,
- int appWidgetId) {
- Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
- if (options == null) {
- return EMPTY_KEY;
- }
- return getPeopleTileKeyFromBundle(options);
- }
-
/** Gets {@link PeopleTileKey} from Bundle {@code options}. */
public static PeopleTileKey getPeopleTileKeyFromBundle(Bundle options) {
String pkg = options.getString(PACKAGE_NAME, EMPTY_STRING);
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index ea1724f..9e0dd72 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -136,6 +136,9 @@
private Map<String, Set<String>> mNotificationKeyToWidgetIdsMatchedByUri = new HashMap<>();
private boolean mRegisteredReceivers;
+ @GuardedBy("mLock")
+ public static Map<Integer, PeopleSpaceTile> mTiles = new HashMap<>();
+
@Inject
public PeopleSpaceWidgetManager(Context context, LauncherApps launcherApps,
NotificationEntryManager notificationEntryManager,
@@ -252,8 +255,7 @@
if (tile == null) {
Log.e(TAG, "Matching conversation not found for shortcut ID");
}
- Bundle options = mAppWidgetManager.getAppWidgetOptions(appWidgetId);
- updateAppWidgetViews(appWidgetId, tile, options);
+ updateAppWidgetOptionsAndView(appWidgetId, tile);
widgetIdToTile.put(appWidgetId, tile);
if (tile != null) {
registerConversationListenerIfNeeded(appWidgetId,
@@ -289,7 +291,14 @@
/** Updates tile in app widget options and the current view. */
public void updateAppWidgetOptionsAndView(int appWidgetId, PeopleSpaceTile tile) {
- Bundle options = AppWidgetOptionsHelper.setPeopleTile(mAppWidgetManager, appWidgetId, tile);
+ if (tile == null) {
+ if (DEBUG) Log.w(TAG, "Requested to store null tile");
+ return;
+ }
+ synchronized (mTiles) {
+ mTiles.put(appWidgetId, tile);
+ }
+ Bundle options = mAppWidgetManager.getAppWidgetOptions(appWidgetId);
updateAppWidgetViews(appWidgetId, tile, options);
}
@@ -299,8 +308,11 @@
*/
@Nullable
public PeopleSpaceTile getTileForExistingWidget(int appWidgetId) {
- // First, check if tile is cached in AppWidgetOptions.
- PeopleSpaceTile tile = AppWidgetOptionsHelper.getPeopleTile(mAppWidgetManager, appWidgetId);
+ // First, check if tile is cached in memory.
+ PeopleSpaceTile tile;
+ synchronized (mTiles) {
+ tile = mTiles.get(appWidgetId);
+ }
if (tile != null) {
if (DEBUG) Log.d(TAG, "People Tile is cached for widget: " + appWidgetId);
return tile;
@@ -781,7 +793,6 @@
} catch (Exception e) {
Log.w(TAG, "Exception caching shortcut:" + e);
}
-
updateAppWidgetOptionsAndView(appWidgetId, tile);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index c69956f..4a8ecc6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -242,35 +242,26 @@
.addFloat(mDateView, "alpha", 0, 1)
.addFloat(mSecurityHeaderView, "alpha", 0, 1)
.addFloat(mQSCarriers, "alpha", 0, 1);
-
- if (noCallingIcon != null || callStrengthIcon != null) {
- if (noCallingIcon != null) {
- builder.addFloat(noCallingIcon, "alpha", 1, 0);
+ builder.setListener(new TouchAnimator.ListenerAdapter() {
+ @Override
+ public void onAnimationAtEnd() {
+ mIconContainer.addIgnoredSlot(mMobileSlotName);
+ mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
}
- if (callStrengthIcon != null) {
- builder.addFloat(callStrengthIcon, "alpha", 1, 0);
+
+ @Override
+ public void onAnimationStarted() {
+ mIconContainer.addIgnoredSlot(mMobileSlotName);
+ mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
}
- builder.setListener(new TouchAnimator.ListenerAdapter() {
- @Override
- public void onAnimationAtEnd() {
- mIconContainer.addIgnoredSlot(mMobileSlotName);
- mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
- }
- @Override
- public void onAnimationStarted() {
- mIconContainer.removeIgnoredSlot(mMobileSlotName);
- mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
- }
-
- @Override
- public void onAnimationAtStart() {
- super.onAnimationAtStart();
- mIconContainer.removeIgnoredSlot(mMobileSlotName);
- mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
- }
- });
- }
+ @Override
+ public void onAnimationAtStart() {
+ super.onAnimationAtStart();
+ mIconContainer.removeIgnoredSlot(mMobileSlotName);
+ mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
+ }
+ });
mAlphaAnimator = builder.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 5afe1c8..c49e054 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -43,6 +43,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
+import com.android.systemui.util.CarrierConfigTracker;
import java.util.function.Consumer;
@@ -71,6 +72,7 @@
private int[] mLastSignalLevel = new int[SIM_SLOTS];
private String[] mLastSignalLevelDescription = new String[SIM_SLOTS];
private final boolean mProviderModel;
+ private final CarrierConfigTracker mCarrierConfigTracker;
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@@ -112,6 +114,10 @@
Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
return;
}
+
+ boolean displayCallStrengthIcon =
+ mCarrierConfigTracker.getCallStrengthConfig(subId);
+
if (statusIcon.icon == R.drawable.ic_qs_no_calling_sms) {
if (statusIcon.visible) {
mInfos[slotIndex] = new CellSignalState(true,
@@ -119,9 +125,14 @@
} else {
// Whenever the no Calling & SMS state is cleared, switched to the last
// known call strength icon.
- mInfos[slotIndex] = new CellSignalState(
- true, mLastSignalLevel[slotIndex],
- mLastSignalLevelDescription[slotIndex], "", false);
+ if (displayCallStrengthIcon) {
+ mInfos[slotIndex] = new CellSignalState(
+ true, mLastSignalLevel[slotIndex],
+ mLastSignalLevelDescription[slotIndex], "", false);
+ } else {
+ mInfos[slotIndex] = new CellSignalState(
+ true, R.drawable.ic_qs_sim_card, "", "", false);
+ }
}
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
} else {
@@ -131,8 +142,13 @@
// shown.
if (mInfos[slotIndex].mobileSignalIconId
!= R.drawable.ic_qs_no_calling_sms) {
- mInfos[slotIndex] = new CellSignalState(true, statusIcon.icon,
- statusIcon.contentDescription, "", false);
+ if (displayCallStrengthIcon) {
+ mInfos[slotIndex] = new CellSignalState(true, statusIcon.icon,
+ statusIcon.contentDescription, "", false);
+ } else {
+ mInfos[slotIndex] = new CellSignalState(
+ true, R.drawable.ic_qs_sim_card, "", "", false);
+ }
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
}
}
@@ -165,7 +181,8 @@
private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter,
@Background Handler bgHandler, @Main Looper mainLooper,
NetworkController networkController,
- CarrierTextManager.Builder carrierTextManagerBuilder, Context context) {
+ CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
+ CarrierConfigTracker carrierConfigTracker) {
if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
mProviderModel = true;
} else {
@@ -178,7 +195,7 @@
.setShowAirplaneMode(false)
.setShowMissingSim(false)
.build();
-
+ mCarrierConfigTracker = carrierConfigTracker;
View.OnClickListener onClickListener = v -> {
if (!v.isVisibleToUser()) {
return;
@@ -228,6 +245,17 @@
return SubscriptionManager.getSlotIndex(subscriptionId);
}
+ private boolean isSingleCarrier() {
+ int carrierCount = 0;
+ for (int i = 0; i < SIM_SLOTS; i++) {
+
+ if (mInfos[i].visible) {
+ carrierCount++;
+ }
+ }
+ return carrierCount == 1;
+ }
+
public void setListening(boolean listening) {
if (listening == mListening) {
return;
@@ -257,6 +285,15 @@
return;
}
+ if (isSingleCarrier()) {
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ if (mInfos[i].visible
+ && mInfos[i].mobileSignalIconId == R.drawable.ic_qs_sim_card) {
+ mInfos[i] = new CellSignalState(true, R.drawable.ic_blank, "", "", false);
+ }
+ }
+ }
+
for (int i = 0; i < SIM_SLOTS; i++) {
mCarrierGroups[i].updateState(mInfos[i]);
}
@@ -363,17 +400,20 @@
private final NetworkController mNetworkController;
private final CarrierTextManager.Builder mCarrierTextControllerBuilder;
private final Context mContext;
+ private final CarrierConfigTracker mCarrierConfigTracker;
@Inject
public Builder(ActivityStarter activityStarter, @Background Handler handler,
@Main Looper looper, NetworkController networkController,
- CarrierTextManager.Builder carrierTextControllerBuilder, Context context) {
+ CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
+ CarrierConfigTracker carrierConfigTracker) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
mNetworkController = networkController;
mCarrierTextControllerBuilder = carrierTextControllerBuilder;
mContext = context;
+ mCarrierConfigTracker = carrierConfigTracker;
}
public Builder setQSCarrierGroup(QSCarrierGroup view) {
@@ -383,7 +423,8 @@
public QSCarrierGroupController build() {
return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
- mNetworkController, mCarrierTextControllerBuilder, mContext);
+ mNetworkController, mCarrierTextControllerBuilder, mContext,
+ mCarrierConfigTracker);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1ec785d47..63adbd0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -933,6 +933,21 @@
}
}
+ public void notifyImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ try {
+ if (mOverviewProxy != null) {
+ mOverviewProxy.onImeWindowStatusChanged(displayId, token, vis, backDisposition,
+ showImeSwitcher);
+ } else {
+ Log.e(TAG_OPS, "Failed to get overview proxy for setting IME status.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to call notifyImeWindowStatus()", e);
+ }
+
+ }
+
private void updateEnabledState() {
final int currentUser = ActivityManagerWrapper.getInstance().getCurrentUserId();
mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
@@ -983,5 +998,7 @@
default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
default void onAssistantGestureCompletion(float velocity) {}
default void startAssistant(Bundle bundle) {}
+ default void onImeWindowStatusChanged(int displayId, IBinder token, int vis,
+ int backDisposition, boolean showImeSwitcher) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
index df9fc63..17e94c4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
@@ -88,7 +88,7 @@
? ACTION_TYPE_EDIT
: ACTION_TYPE_SHARE;
mScreenshotSmartActions.notifyScreenshotAction(
- context, intent.getStringExtra(EXTRA_ID), actionType, false);
+ context, intent.getStringExtra(EXTRA_ID), actionType, false, null);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java
index 35839f3..8d44205 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java
@@ -62,7 +62,7 @@
});
if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) {
mScreenshotSmartActions.notifyScreenshotAction(
- context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false);
+ context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false, null);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
index 6ebab8a..3eafbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
@@ -21,6 +21,7 @@
import android.app.Notification;
import android.content.ComponentName;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.UserHandle;
@@ -107,7 +108,8 @@
* @param action type of notification action invoked.
* @param isSmartAction whether action invoked was a smart action.
*/
- public void notifyAction(String screenshotId, String action, boolean isSmartAction) {
+ public void notifyAction(String screenshotId, String action, boolean isSmartAction,
+ Intent intent) {
if (DEBUG_ACTIONS) {
Log.d(TAG, "SmartActions: notifyAction: return without notify");
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
index 99238cd..0527818 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java
@@ -26,6 +26,7 @@
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
@@ -165,7 +166,7 @@
}
void notifyScreenshotAction(Context context, String screenshotId, String action,
- boolean isSmartAction) {
+ boolean isSmartAction, Intent intent) {
try {
ScreenshotNotificationSmartActionsProvider provider =
SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider(
@@ -174,7 +175,7 @@
Log.d(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b",
provider.getClass(), action, screenshotId, isSmartAction));
}
- provider.notifyAction(screenshotId, action, isSmartAction);
+ provider.notifyAction(screenshotId, action, isSmartAction, intent);
} catch (Throwable e) {
Log.e(TAG, "Error in notifyScreenshotAction: ", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index 3ad922b..f703058 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -60,6 +60,7 @@
}
mScreenshotSmartActions.notifyScreenshotAction(
- context, intent.getStringExtra(EXTRA_ID), actionType, true);
+ context, intent.getStringExtra(EXTRA_ID), actionType, true,
+ pendingIntent.getIntent());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a072de8..5daee6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -492,8 +492,12 @@
return UserHandle.USER_NULL;
}
- @VisibleForTesting
- protected void setVisible(boolean visible) {
+ /**
+ * Sets the visibility of keyguard bottom area, and if the indications are updatable.
+ *
+ * @param visible true to make the area visible and update the indication, false otherwise.
+ */
+ public void setVisible(boolean visible) {
mVisible = visible;
mIndicationArea.setVisibility(visible ? VISIBLE : GONE);
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8f462fe..e49ca13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -31,6 +31,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -176,7 +177,13 @@
viewState.height = getIntrinsicHeight();
viewState.zTranslation = ambientState.getBaseZHeight();
viewState.clipTopAmount = 0;
- viewState.alpha = 1f - ambientState.getHideAmount();
+
+ if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
+ viewState.alpha = Interpolators.getNotificationScrimAlpha(
+ ambientState.getExpansionFraction());
+ } else {
+ viewState.alpha = 1f - ambientState.getHideAmount();
+ }
viewState.belowSpeedBump = mHostLayoutController.getSpeedBumpIndex() == 0;
viewState.hideSensitive = false;
viewState.xTranslation = getTranslationX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index fad7480..eb7854e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.dagger;
+import android.app.IActivityManager;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Handler;
@@ -68,6 +69,7 @@
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
+import java.util.concurrent.Executor;
import dagger.Binds;
import dagger.Lazy;
@@ -239,10 +241,13 @@
CommonNotifCollection notifCollection,
FeatureFlags featureFlags,
SystemClock systemClock,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter,
+ @Main Executor mainExecutor,
+ IActivityManager iActivityManager) {
OngoingCallController ongoingCallController =
new OngoingCallController(
- notifCollection, featureFlags, systemClock, activityStarter);
+ notifCollection, featureFlags, systemClock, activityStarter, mainExecutor,
+ iActivityManager);
ongoingCallController.init();
return ongoingCallController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 506d8a1..120f973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2068,6 +2068,7 @@
int height = 0;
float previousPaddingRequest = mPaddingBetweenElements;
int numShownItems = 0;
+ int numShownNotifs = 0;
boolean finish = false;
int maxDisplayedNotifications = mMaxDisplayedNotifications;
ExpandableView previousView = null;
@@ -2077,7 +2078,7 @@
if (expandableView.getVisibility() != View.GONE
&& !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
boolean limitReached = maxDisplayedNotifications != -1
- && numShownItems >= maxDisplayedNotifications;
+ && numShownNotifs >= maxDisplayedNotifications;
final float viewHeight;
if (limitReached) {
viewHeight = mShelf.getIntrinsicHeight();
@@ -2090,7 +2091,11 @@
}
height += calculateGapHeight(previousView, expandableView, numShownItems);
height += viewHeight;
+
numShownItems++;
+ if (!(expandableView instanceof MediaHeaderView)) {
+ numShownNotifs++;
+ }
previousView = expandableView;
if (finish) {
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 413048d..d94d030 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -24,6 +24,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
@@ -374,7 +375,13 @@
ExpandableView view = algorithmState.visibleChildren.get(i);
ExpandableViewState viewState = view.getViewState();
viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
- viewState.alpha = 1f - ambientState.getHideAmount();
+
+ if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
+ viewState.alpha = Interpolators.getNotificationScrimAlpha(
+ ambientState.getExpansionFraction());
+ } else {
+ viewState.alpha = 1f - ambientState.getHideAmount();
+ }
if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
// Even if we're not scrolled away we're in view and we're also not in the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 16bed6f..2b51b56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -105,12 +105,7 @@
private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() {
@Override
- public void onOngoingCallStarted(boolean animate) {
- disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
- }
-
- @Override
- public void onOngoingCallEnded(boolean animate) {
+ public void onOngoingCallStateChanged(boolean animate) {
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, animate);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index f9a644f..a3efcd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -697,16 +697,6 @@
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
- if (mAmbientState.isExpansionChanging()
- && !mIsFlinging // Fling already uses interpolated height from end of swipe
- && !mAmbientState.isOnKeyguard()
- && !mAmbientState.isDozing()
- && !mAmbientState.isPulsing()) {
- final float fraction = h / mView.getHeight();
- final float interpolatedFraction = new PathInterpolator(0.2f, 0.8f, 0.8f, 1f)
- .getInterpolation(fraction);
- h = interpolatedFraction * mView.getHeight();
- }
maybeOverScrollForShadeFlingOpen(h);
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index f1405de..ed7ab6cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -673,11 +673,14 @@
}
}
+ // Disabling for now, but keeping the log
+ /*
mIconController.setIconVisibility(mSlotCamera, showCamera);
mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
if (mPrivacyItemController.getLocationAvailable()) {
mIconController.setIconVisibility(mSlotLocation, showLocation);
}
+ */
mPrivacyLogger.logStatusBarIconsVisible(showCamera, showMicrophone, showLocation);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a952db2..c34fa2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -42,6 +42,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -810,15 +811,7 @@
}
private float getInterpolatedFraction() {
- float frac = mPanelExpansion;
- // let's start this 20% of the way down the screen
- frac = frac * 1.2f - 0.2f;
- if (frac <= 0) {
- return 0;
- } else {
- // woo, special effects
- return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * Math.pow(1f - frac, 2f))));
- }
+ return Interpolators.getNotificationScrimAlpha(mPanelExpansion);
}
private void setScrimAlpha(ScrimView scrim, float alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bd17d00..cae7e35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -393,7 +393,6 @@
private final Object mQueueLock = new Object();
- private final StatusBarIconController mIconController;
private final PulseExpansionHandler mPulseExpansionHandler;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
private final KeyguardBypassController mKeyguardBypassController;
@@ -720,7 +719,7 @@
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarIconController statusBarIconController,
+ StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -806,7 +805,7 @@
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mIconController = statusBarIconController;
+ mSignalPolicy = signalPolicy;
mPulseExpansionHandler = pulseExpansionHandler;
mWakeUpCoordinator = notificationWakeUpCoordinator;
mKeyguardBypassController = keyguardBypassController;
@@ -1015,7 +1014,6 @@
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy.init();
- mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
mKeyguardStateController.addCallback(this);
startKeyguard();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 3445826..142cf21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -25,6 +25,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
@@ -33,12 +34,16 @@
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.CarrierConfigTracker;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import javax.inject.Inject;
+/** Controls the signal policies for icons shown in the StatusBar. **/
+@SysUISingleton
public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,
SecurityController.SecurityControllerCallback, Tunable {
private static final String TAG = "StatusBarSignalPolicy";
@@ -57,6 +62,7 @@
private final NetworkController mNetworkController;
private final SecurityController mSecurityController;
private final Handler mHandler = Handler.getMain();
+ private final CarrierConfigTracker mCarrierConfigTracker;
private boolean mHideAirplane;
private boolean mHideMobile;
@@ -75,7 +81,9 @@
new ArrayList<CallIndicatorIconState>();
private WifiIconState mWifiIconState = new WifiIconState();
- public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
+ @Inject
+ public StatusBarSignalPolicy(Context context, StatusBarIconController iconController,
+ CarrierConfigTracker carrierConfigTracker) {
mContext = context;
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
@@ -95,6 +103,7 @@
Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
+ mCarrierConfigTracker = carrierConfigTracker;
}
public void destroy() {
@@ -215,8 +224,12 @@
state.callStrengthResId = statusIcon.icon;
state.callStrengthDescription = statusIcon.contentDescription;
}
- mIconController.setCallStrengthIcons(mSlotCallStrength,
- CallIndicatorIconState.copyStates(mCallIndicatorStates));
+ if (mCarrierConfigTracker.getCallStrengthConfig(subId)) {
+ mIconController.setCallStrengthIcons(mSlotCallStrength,
+ CallIndicatorIconState.copyStates(mCallIndicatorStates));
+ } else {
+ mIconController.removeIcon(mSlotCallStrength, subId);
+ }
mIconController.setNoCallingIcons(mSlotNoCalling,
CallIndicatorIconState.copyStates(mCallIndicatorStates));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index ae11a74..d0d2cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -88,10 +88,10 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -134,7 +134,7 @@
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarIconController statusBarIconController,
+ StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -221,7 +221,7 @@
lightBarController,
autoHideController,
keyguardUpdateMonitor,
- statusBarIconController,
+ signalPolicy,
pulseExpansionHandler,
notificationWakeUpCoordinator,
keyguardBypassController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 51bb643..6d1df5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone.ongoingcall
+import android.app.ActivityManager
+import android.app.IActivityManager
+import android.app.IUidObserver
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
import android.content.Intent
@@ -25,6 +28,7 @@
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -32,6 +36,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.Executor
import javax.inject.Inject
/**
@@ -42,12 +47,17 @@
private val notifCollection: CommonNotifCollection,
private val featureFlags: FeatureFlags,
private val systemClock: SystemClock,
- private val activityStarter: ActivityStarter
+ private val activityStarter: ActivityStarter,
+ @Main private val mainExecutor: Executor,
+ private val iActivityManager: IActivityManager
) : CallbackController<OngoingCallListener> {
/** Null if there's no ongoing call. */
private var ongoingCallInfo: OngoingCallInfo? = null
+ /** True if the application managing the call is visible to the user. */
+ private var isCallAppVisible: Boolean = true
private var chipView: ViewGroup? = null
+ private var uidObserver: IUidObserver.Stub? = null
private val mListeners: MutableList<OngoingCallListener> = mutableListOf()
@@ -67,8 +77,9 @@
override fun onEntryUpdated(entry: NotificationEntry) {
if (isOngoingCallNotification(entry)) {
ongoingCallInfo = OngoingCallInfo(
- entry.sbn.notification.`when`,
- entry.sbn.notification.contentIntent.intent)
+ entry.sbn.notification.`when`,
+ entry.sbn.notification.contentIntent.intent,
+ entry.sbn.uid)
updateChip()
}
}
@@ -76,7 +87,10 @@
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
if (isOngoingCallNotification(entry)) {
ongoingCallInfo = null
- mListeners.forEach { l -> l.onOngoingCallEnded(animate = true) }
+ mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
+ if (uidObserver != null) {
+ iActivityManager.unregisterUidObserver(uidObserver)
+ }
}
}
}
@@ -100,9 +114,13 @@
}
/**
- * Returns true if there's an active ongoing call that can be displayed in a status bar chip.
+ * Returns true if there's an active ongoing call that should be displayed in a status bar chip.
*/
- fun hasOngoingCall(): Boolean = ongoingCallInfo != null
+ fun hasOngoingCall(): Boolean {
+ return ongoingCallInfo != null &&
+ // When the user is in the phone app, don't show the chip.
+ !isCallAppVisible
+ }
override fun addCallback(listener: OngoingCallListener) {
synchronized(mListeners) {
@@ -137,7 +155,9 @@
ActivityLaunchAnimator.Controller.fromView(it))
}
- mListeners.forEach { l -> l.onOngoingCallStarted(animate = true) }
+ setUpUidObserver(currentOngoingCallInfo)
+
+ mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
} else {
// If we failed to update the chip, don't store the ongoing call info. Then
// [hasOngoingCall] will return false and we fall back to typical notification handling.
@@ -150,9 +170,52 @@
}
}
+ /**
+ * Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call.
+ */
+ private fun setUpUidObserver(currentOngoingCallInfo: OngoingCallInfo) {
+ isCallAppVisible = isProcessVisibleToUser(
+ iActivityManager.getUidProcessState(currentOngoingCallInfo.uid, null))
+
+ uidObserver = object : IUidObserver.Stub() {
+ override fun onUidStateChanged(
+ uid: Int, procState: Int, procStateSeq: Long, capability: Int) {
+ if (uid == currentOngoingCallInfo.uid) {
+ val oldIsCallAppVisible = isCallAppVisible
+ isCallAppVisible = isProcessVisibleToUser(procState)
+ if (oldIsCallAppVisible != isCallAppVisible) {
+ // Animations may be run as a result of the call's state change, so ensure
+ // the listener is notified on the main thread.
+ mainExecutor.execute {
+ mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
+ }
+ }
+ }
+ }
+
+ override fun onUidGone(uid: Int, disabled: Boolean) {}
+ override fun onUidActive(uid: Int) {}
+ override fun onUidIdle(uid: Int, disabled: Boolean) {}
+ override fun onUidCachedChanged(uid: Int, cached: Boolean) {}
+ }
+
+ iActivityManager.registerUidObserver(
+ uidObserver,
+ ActivityManager.UID_OBSERVER_PROCSTATE,
+ ActivityManager.PROCESS_STATE_UNKNOWN,
+ null
+ )
+ }
+
+ /** Returns true if the given [procState] represents a process that's visible to the user. */
+ private fun isProcessVisibleToUser(procState: Int): Boolean {
+ return procState <= ActivityManager.PROCESS_STATE_TOP
+ }
+
private class OngoingCallInfo(
val callStartTime: Long,
- val intent: Intent
+ val intent: Intent,
+ val uid: Int
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
index 7c583a1..7a12430 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallListener.kt
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.phone.ongoingcall
-/** A listener that's notified when an ongoing call is started or ended. */
+/** A listener that's notified when the state of an ongoing call has changed. */
interface OngoingCallListener {
- /** Called when an ongoing call is started. */
- fun onOngoingCallStarted(animate: Boolean)
- /** Called when an ongoing call is ended. */
- fun onOngoingCallEnded(animate: Boolean)
+ /**
+ * Called when the state of an ongoing call has changed in any way that may affect view
+ * visibility (including call starting, call stopping, application managing the call becoming
+ * visible or invisible).
+ */
+ fun onOngoingCallStateChanged(animate: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 044f52f..ce08075 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -61,6 +61,7 @@
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.util.CarrierConfigTracker;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -78,6 +79,7 @@
private static final int IMS_TYPE_WLAN = 2;
private static final int IMS_TYPE_WLAN_CROSS_SIM = 3;
private final TelephonyManager mPhone;
+ private final CarrierConfigTracker mCarrierConfigTracker;
private final ImsMmTelManager mImsMmTelManager;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
@@ -123,10 +125,12 @@
public MobileSignalController(Context context, Config config, boolean hasMobileData,
TelephonyManager phone, CallbackHandler callbackHandler,
NetworkControllerImpl networkController, SubscriptionInfo info,
- SubscriptionDefaults defaults, Looper receiverLooper) {
+ SubscriptionDefaults defaults, Looper receiverLooper,
+ CarrierConfigTracker carrierConfigTracker) {
super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
networkController);
+ mCarrierConfigTracker = carrierConfigTracker;
mConfig = config;
mPhone = phone;
mDefaults = defaults;
@@ -583,7 +587,7 @@
mTelephonyDisplayInfo = mobileStatus.telephonyDisplayInfo;
int lastVoiceState = mServiceState != null ? mServiceState.getState() : -1;
mServiceState = mobileStatus.serviceState;
- int currentVoiceState = mServiceState != null ? mServiceState.getState() : -1;
+ int currentVoiceState = mServiceState != null ? mServiceState.getState() : -1;
// Only update the no calling Status in the below scenarios
// 1. The first valid voice state has been received
// 2. The voice state has been changed and either the last or current state is
@@ -594,12 +598,29 @@
|| (lastVoiceState == ServiceState.STATE_IN_SERVICE
|| currentVoiceState == ServiceState.STATE_IN_SERVICE))) {
boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
- IconState statusIcon = new IconState(isNoCalling, R.drawable.ic_qs_no_calling_sms,
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
}
}
+ void updateNoCallingState() {
+ int currentVoiceState = mServiceState != null ? mServiceState.getState() : -1;
+ boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ private boolean hideNoCalling() {
+ return mNetworkController.hasDefaultNetwork()
+ && mCarrierConfigTracker.getNoCallingConfig(mSubscriptionInfo.getSubscriptionId());
+ }
+
private int getCallStrengthIcon(int level, boolean isWifi) {
return isWifi ? TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[level]
: TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[level];
@@ -616,7 +637,9 @@
void refreshCallIndicator(SignalCallback callback) {
boolean isNoCalling = mServiceState != null
&& mServiceState.getState() != ServiceState.STATE_IN_SERVICE;
- IconState statusIcon = new IconState(isNoCalling, R.drawable.ic_qs_no_calling_sms,
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
callback.setCallIndicator(statusIcon, mSubscriptionInfo.getSubscriptionId());
@@ -646,7 +669,6 @@
if (!mProviderModel) {
return;
}
- Log.d("mTag", "notifyWifiLevelChange " + mImsType);
mLastWlanLevel = level;
if (mImsType != IMS_TYPE_WLAN) {
return;
@@ -662,7 +684,6 @@
if (!mProviderModel) {
return;
}
- Log.d("mTag", "notifyDefaultMobileLevelChange " + mImsType);
mLastWlanCrossSimLevel = level;
if (mImsType != IMS_TYPE_WLAN_CROSS_SIM) {
return;
@@ -681,7 +702,6 @@
int newLevel = getSignalLevel(signalStrength);
if (newLevel != mLastLevel) {
mLastLevel = newLevel;
- Log.d("mTag", "notifyMobileLevelChangeIfNecessary " + mImsType);
mLastWwanLevel = newLevel;
if (mImsType == IMS_TYPE_WWAN) {
IconState statusIcon = new IconState(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index f683603..f45218d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -74,6 +74,7 @@
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
+import com.android.systemui.util.CarrierConfigTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -122,6 +123,7 @@
private final Object mLock = new Object();
private final boolean mProviderModel;
private Config mConfig;
+ private final CarrierConfigTracker mCarrierConfigTracker;
private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -212,7 +214,8 @@
@Nullable WifiManager wifiManager,
NetworkScoreManager networkScoreManager,
AccessPointControllerImpl accessPointController,
- DemoModeController demoModeController) {
+ DemoModeController demoModeController,
+ CarrierConfigTracker carrierConfigTracker) {
this(context, connectivityManager,
telephonyManager,
telephonyListenerManager,
@@ -228,7 +231,8 @@
new SubscriptionDefaults(),
deviceProvisionedController,
broadcastDispatcher,
- demoModeController);
+ demoModeController,
+ carrierConfigTracker);
mReceiverHandler.post(mRegisterListeners);
}
@@ -246,7 +250,8 @@
SubscriptionDefaults defaultsHandler,
DeviceProvisionedController deviceProvisionedController,
BroadcastDispatcher broadcastDispatcher,
- DemoModeController demoModeController) {
+ DemoModeController demoModeController,
+ CarrierConfigTracker carrierConfigTracker) {
mContext = context;
mTelephonyListenerManager = telephonyListenerManager;
mConfig = config;
@@ -262,6 +267,7 @@
mConnectivityManager = connectivityManager;
mHasMobileDataFeature = telephonyManager.isDataCapable();
mDemoModeController = demoModeController;
+ mCarrierConfigTracker = carrierConfigTracker;
// telephony
mPhone = telephonyManager;
@@ -574,6 +580,10 @@
return mWifiSignalController.isCarrierMergedWifi(subId);
}
+ boolean hasDefaultNetwork() {
+ return !mNoDefaultNetwork;
+ }
+
boolean isNonCarrierWifiNetworkAvailable() {
return !mNoNetworksAvailable;
}
@@ -884,7 +894,7 @@
MobileSignalController controller = new MobileSignalController(mContext, mConfig,
mHasMobileDataFeature, mPhone.createForSubscriptionId(subId),
mCallbackHandler, this, subscriptions.get(i),
- mSubDefaults, mReceiverHandler.getLooper());
+ mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker);
controller.setUserSetupComplete(mUserSetup);
mMobileSignalControllers.put(subId, controller);
if (subscriptions.get(i).getSimSlotIndex() == 0) {
@@ -1027,6 +1037,10 @@
mNoDefaultNetwork = mConnectedTransports.isEmpty();
mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
mNoNetworksAvailable);
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.updateNoCallingState();
+ }
notifyAllListeners();
}
}
@@ -1334,8 +1348,8 @@
null, null, null, "", false, null, null);
MobileSignalController controller = new MobileSignalController(mContext,
mConfig, mHasMobileDataFeature,
- mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this, info,
- mSubDefaults, mReceiverHandler.getLooper());
+ mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this,
+ info, mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker);
mMobileSignalControllers.put(id, controller);
controller.getState().userSetup = true;
return info;
diff --git a/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
new file mode 100644
index 0000000..02a07e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.util.SparseArray;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Tracks the Carrier Config values.
+ */
+@SysUISingleton
+public class CarrierConfigTracker extends BroadcastReceiver {
+ private final SparseArray<Boolean> mCallStrengthConfigs = new SparseArray<>();
+ private final SparseArray<Boolean> mNoCallingConfigs = new SparseArray<>();
+ private final CarrierConfigManager mCarrierConfigManager;
+ private final boolean mDefaultCallStrengthConfig;
+ private final boolean mDefaultNoCallingConfig;
+
+ @Inject
+ public CarrierConfigTracker(Context context) {
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+ context.registerReceiver(
+ this, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ mDefaultCallStrengthConfig =
+ CarrierConfigManager.getDefaultConfig().getBoolean(
+ CarrierConfigManager.KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL);
+ mDefaultNoCallingConfig =
+ CarrierConfigManager.getDefaultConfig().getBoolean(
+ CarrierConfigManager.KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED) {
+ int subId = intent.getIntExtra(
+ CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ return;
+ }
+ PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId);
+ if (b != null) {
+ boolean hideNoCallingConfig = b.getBoolean(
+ CarrierConfigManager.KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL);
+ boolean displayCallStrengthIcon = b.getBoolean(
+ CarrierConfigManager.KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL);
+ mCallStrengthConfigs.put(subId, displayCallStrengthIcon);
+ mNoCallingConfigs.put(subId, hideNoCallingConfig);
+ }
+ }
+ }
+
+ /**
+ * Returns the KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL value for the given subId.
+ */
+ public boolean getCallStrengthConfig(int subId) {
+ if (mCallStrengthConfigs.indexOfKey(subId) >= 0) {
+ return mCallStrengthConfigs.get(subId);
+ }
+ return mDefaultCallStrengthConfig;
+ }
+
+ /**
+ * Returns the KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL value for the given subId.
+ */
+ public boolean getNoCallingConfig(int subId) {
+ if (mNoCallingConfigs.indexOfKey(subId) >= 0) {
+ return mNoCallingConfigs.get(subId);
+ }
+ return mDefaultNoCallingConfig;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index d07a8da..495489f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
@@ -41,10 +42,11 @@
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
+import androidx.annotation.Nullable;
+
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -74,6 +76,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
@SmallTest
@@ -117,12 +120,12 @@
@Mock
ConfigurationController mConfigurationController;
@Mock
+ Optional<BcSmartspaceDataPlugin> mOptionalSmartspaceDataProvider;
+ @Mock
BcSmartspaceDataPlugin mSmartspaceDataProvider;
@Mock
SmartspaceView mSmartspaceView;
@Mock
- SystemUIFactory mSystemUIFactory;
- @Mock
ActivityStarter mActivityStarter;
@Mock
FalsingManager mFalsingManager;
@@ -162,7 +165,6 @@
when(mFeatureFlags.isSmartspaceEnabled()).thenReturn(true);
when(mView.isAttachedToWindow()).thenReturn(true);
when(mResources.getString(anyInt())).thenReturn("h:mm");
- when(mSystemUIFactory.getSmartspaceDataProvider()).thenReturn(mSmartspaceDataProvider);
mController = new KeyguardClockSwitchController(
mView,
mStatusBarStateController,
@@ -175,14 +177,14 @@
mExecutor,
mBatteryController,
mConfigurationController,
- mSystemUIFactory,
mActivityStarter,
mFalsingManager,
mKeyguardUpdateMonitor,
mBypassController,
mHandler,
mUserTracker,
- mSecureSettings
+ mSecureSettings,
+ mOptionalSmartspaceDataProvider
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
@@ -190,6 +192,8 @@
mStatusArea = new View(getContext());
when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+ when(mOptionalSmartspaceDataProvider.isPresent()).thenReturn(true);
+ when(mOptionalSmartspaceDataProvider.get()).thenReturn(mSmartspaceDataProvider);
when(mSmartspaceDataProvider.getView(any())).thenReturn(mSmartspaceView);
}
@@ -260,7 +264,7 @@
@Test
public void testSmartspaceEnabledNoDataProviderShowsKeyguardStatusArea() {
when(mFeatureFlags.isSmartspaceEnabled()).thenReturn(true);
- when(mSystemUIFactory.getSmartspaceDataProvider()).thenReturn(null);
+ when(mOptionalSmartspaceDataProvider.isPresent()).thenReturn(false);
mController.init();
assertEquals(View.VISIBLE, mStatusArea.getVisibility());
@@ -389,5 +393,7 @@
public void setIntentStarter(IntentStarter intentStarter) { }
public void setFalsingManager(FalsingManager falsingManager) { }
+
+ public void setDnd(@Nullable Icon dndIcon, @Nullable String description) { }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
index 47f4183..eac68f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
@@ -62,8 +62,10 @@
final View view = new View(mContext);
mRotationButton = mock(RotationButton.class);
- mRotationButtonController = spy(new RotationButtonController(mContext, 0, 0,
- mRotationButton, (visibility) -> {}));
+ mRotationButtonController = new RotationButtonController(mContext, 0, 0);
+ mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {});
+ // Due to a mockito issue, only spy the object after setting the initial state
+ mRotationButtonController = spy(mRotationButtonController);
final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class);
doReturn(view).when(mRotationButton).getCurrentView();
doReturn(true).when(mRotationButton).acceptRotationProposal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index 0dd1f68..8983ff8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.people;
import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
-import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE;
import static com.google.common.truth.Truth.assertThat;
@@ -200,7 +199,6 @@
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
mOptions = new Bundle();
- mOptions.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE);
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 228e5e8..5c70a4ef2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -29,7 +29,6 @@
import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT;
import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;
-import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE;
import static com.google.common.truth.Truth.assertThat;
@@ -140,7 +139,6 @@
MockitoAnnotations.initMocks(this);
mOptions = new Bundle();
- mOptions.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE);
when(mMockContext.getString(R.string.birthday_status)).thenReturn(
mContext.getString(R.string.birthday_status));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index f31f326..107ce28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -51,7 +51,6 @@
import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
-import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE;
import static com.google.common.truth.Truth.assertThat;
@@ -192,6 +191,7 @@
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ private static final long SBN_POST_TIME = 567L;
private ShortcutInfo mShortcutInfo;
private NotificationEntry mNotificationEntry;
@@ -474,8 +474,6 @@
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(anyInt(), any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any());
}
@@ -495,8 +493,6 @@
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(anyInt(), any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any());
}
@@ -515,8 +511,6 @@
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(anyInt(), any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any());
}
@@ -538,8 +532,6 @@
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(anyInt(), any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any());
}
@@ -559,8 +551,6 @@
mManager.updateWidgetsWithConversationChanged(conversationChannel);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(anyInt(), any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any());
}
@@ -578,11 +568,7 @@
mManager.updateWidgetsWithConversationChanged(conversationChannel);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getStatuses()).containsExactly(status);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
@@ -599,14 +585,8 @@
mManager.updateWidgetsWithConversationChanged(conversationChannel);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
any());
}
@@ -626,12 +606,9 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
+ assertThat(tile.getLastInteractionTimestamp()).isEqualTo(SBN_POST_TIME);
assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
@@ -647,14 +624,8 @@
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
any());
}
@@ -672,14 +643,8 @@
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, never())
- .updateAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
- any());
verify(mAppWidgetManager, never()).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
any());
}
@@ -700,12 +665,7 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
-
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tile.getNotificationContent())
.isEqualTo(mContext.getString(R.string.missed_call));
@@ -729,12 +689,7 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
-
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
@@ -758,21 +713,13 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(
NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI),
- mBundleArgumentCaptor.capture());
- Bundle bundleForSameUriTile = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithSameUri = bundleForSameUriTile.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI);
assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI),
@@ -801,19 +748,12 @@
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn.cloneLight(), 0);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(null);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(null);
verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, times(2))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI),
- mBundleArgumentCaptor.capture());
- Bundle bundleForSameUriTile = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithSameUri = bundleForSameUriTile.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI);
assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(null);
assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(null);
verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI),
@@ -847,21 +787,13 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(
NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI),
- mBundleArgumentCaptor.capture());
- Bundle bundleForSameUriTile = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithSameUri = bundleForSameUriTile.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI);
assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI),
@@ -900,20 +832,13 @@
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(
NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
// Do not update since notification doesn't include a Person reference.
- verify(mAppWidgetManager, times(0))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI),
- any());
verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI),
any());
}
@@ -939,20 +864,13 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(
NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
// Do not update since missing permission to read contacts.
- verify(mAppWidgetManager, times(0))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_DIFFERENT_URI),
- any());
verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_DIFFERENT_URI),
any());
}
@@ -977,23 +895,14 @@
NotifEvent notif1 = mNoMan.postNotif(builder);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(
NOTIFICATION_CONTENT_1);
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
// Do not update since missing permission to read contacts.
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI),
- mBundleArgumentCaptor.capture());
- Bundle noNotificationBundle = requireNonNull(mBundleArgumentCaptor.getValue());
- PeopleSpaceTile tileNoNotification =
- noNotificationBundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tileNoNotification = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI);
assertThat(tileNoNotification.getNotificationKey()).isNull();
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI),
any());
@@ -1010,21 +919,20 @@
.setSbn(sbn)
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
+ long timestampBeforeNotificationClear = System.currentTimeMillis();
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
mClock.advanceTime(MIN_LINGER_DURATION);
- verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationKey()).isEqualTo(null);
+ assertThat(tile.getLastInteractionTimestamp()).isLessThan(
+ timestampBeforeNotificationClear);
assertThat(tile.getNotificationContent()).isEqualTo(null);
assertThat(tile.getNotificationDataUri()).isEqualTo(null);
verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
any());
}
-
@Test
public void testAddThenReconfigureWidgetsUpdatesStorageCacheAndListeners()
throws Exception {
@@ -1131,7 +1039,6 @@
@Test
public void testOnAppWidgetOptionsChangedNoWidgetAdded() {
Bundle newOptions = new Bundle();
- newOptions.putParcelable(OPTIONS_PEOPLE_TILE, PERSON_TILE);
mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions);
@@ -1166,10 +1073,9 @@
mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions);
- verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(
+ verify(mAppWidgetManager, times(1)).updateAppWidgetOptions(
eq(SECOND_WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture());
- List<Bundle> bundles = mBundleArgumentCaptor.getAllValues();
- Bundle first = bundles.get(0);
+ Bundle first = mBundleArgumentCaptor.getValue();
assertThat(first.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING))
.isEqualTo(EMPTY_STRING);
assertThat(first.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID);
@@ -1177,21 +1083,6 @@
verify(mLauncherApps, times(1)).cacheShortcuts(eq(TEST_PACKAGE_A),
eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)),
eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
-
- Bundle second = bundles.get(1);
- PeopleSpaceTile tile = second.getParcelable(OPTIONS_PEOPLE_TILE);
- assertThat(tile.getId()).isEqualTo(SHORTCUT_ID);
-
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
- assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).contains(
- String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT));
- SharedPreferences widgetSp = mContext.getSharedPreferences(
- String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT),
- Context.MODE_PRIVATE);
- assertThat(widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(TEST_PACKAGE_A);
- assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING))
- .isEqualTo(SHORTCUT_ID);
- assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0);
}
@Test
@@ -1306,11 +1197,7 @@
public void testUpdateWidgetsOnStateChange() {
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.isPackageSuspended()).isFalse();
assertThat(tile.isUserQuieted()).isFalse();
assertThat(tile.canBypassDnd()).isFalse();
@@ -1325,11 +1212,7 @@
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.isPackageSuspended()).isFalse();
assertThat(tile.isUserQuieted()).isTrue();
assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS);
@@ -1341,11 +1224,7 @@
mManager.updateWidgetsOnStateChange(ACTION_PACKAGES_SUSPENDED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- Bundle bundle = mBundleArgumentCaptor.getValue();
- PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.isPackageSuspended()).isTrue();
assertThat(tile.isUserQuieted()).isFalse();
assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS);
@@ -1357,10 +1236,7 @@
mManager.updateWidgetsOnStateChange(NotificationManager
.ACTION_INTERRUPTION_FILTER_CHANGED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS);
}
@@ -1375,10 +1251,7 @@
mManager.updateWidgetsOnStateChange(NotificationManager
.ACTION_INTERRUPTION_FILTER_CHANGED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS);
}
@@ -1394,10 +1267,7 @@
mManager.updateWidgetsOnStateChange(NotificationManager
.ACTION_INTERRUPTION_FILTER_CHANGED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(
expected | SHOW_IMPORTANT_CONVERSATIONS);
}
@@ -1412,10 +1282,7 @@
mManager.updateWidgetsOnStateChange(NotificationManager
.ACTION_INTERRUPTION_FILTER_CHANGED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS);
}
@@ -1430,10 +1297,7 @@
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONTACTS);
}
@@ -1448,10 +1312,7 @@
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_STARRED_CONTACTS);
}
@@ -1464,10 +1325,7 @@
mManager.updateWidgetsOnStateChange(NotificationManager
.ACTION_INTERRUPTION_FILTER_CHANGED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS);
}
@@ -1482,10 +1340,7 @@
mManager.updateWidgetsOnStateChange(ACTION_BOOT_COMPLETED);
- verify(mAppWidgetManager, times(1))
- .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
- mBundleArgumentCaptor.capture());
- PeopleSpaceTile tile = mBundleArgumentCaptor.getValue().getParcelable(OPTIONS_PEOPLE_TILE);
+ PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT);
assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS);
}
@@ -1513,7 +1368,6 @@
private void addTileForWidget(PeopleSpaceTile tile, int widgetId) throws Exception {
setStorageForTile(tile.getId(), tile.getPackageName(), widgetId, tile.getContactUri());
Bundle options = new Bundle();
- options.putParcelable(OPTIONS_PEOPLE_TILE, tile);
ConversationChannel channel = getConversationWithShortcutId(new PeopleTileKey(tile));
when(mAppWidgetManager.getAppWidgetOptions(eq(widgetId)))
.thenReturn(options);
@@ -1596,6 +1450,7 @@
.setNotification(notification)
.setPkg(TEST_PACKAGE_A)
.setUid(0)
+ .setPostTime(SBN_POST_TIME)
.setUser(new UserHandle(0))
.build();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 59a5f03..876acc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -37,6 +37,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
+import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -66,6 +67,8 @@
private CarrierTextManager.Builder mCarrierTextControllerBuilder;
@Mock
private CarrierTextManager mCarrierTextManager;
+ @Mock
+ private CarrierConfigTracker mCarrierConfigTracker;
private TestableLooper mTestableLooper;
@Before
@@ -99,7 +102,7 @@
mQSCarrierGroupController = new QSCarrierGroupController.Builder(
mActivityStarter, handler, TestableLooper.get(this).getLooper(),
- mNetworkController, mCarrierTextControllerBuilder, mContext)
+ mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker)
.setQSCarrierGroup(mQSCarrierGroup)
.build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
index 9a1126f..bfe875c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
@@ -115,7 +115,8 @@
actionProxyReceiver.onReceive(mContext, mIntent);
verify(mMockScreenshotSmartActions, never())
- .notifyScreenshotAction(any(Context.class), anyString(), anyString(), anyBoolean());
+ .notifyScreenshotAction(any(Context.class), anyString(), anyString(), anyBoolean(),
+ any(Intent.class));
}
@Test
@@ -128,7 +129,7 @@
actionProxyReceiver.onReceive(mContext, mIntent);
verify(mMockScreenshotSmartActions).notifyScreenshotAction(
- mContext, testId, ACTION_TYPE_SHARE, false);
+ mContext, testId, ACTION_TYPE_SHARE, false, null);
}
private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java
index 14c7679..664c125 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java
@@ -81,7 +81,8 @@
verify(mMockExecutor, never()).execute(any(Runnable.class));
verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction(
- any(Context.class), any(String.class), any(String.class), anyBoolean());
+ any(Context.class), any(String.class), any(String.class), anyBoolean(),
+ any(Intent.class));
}
@Test
@@ -112,8 +113,8 @@
}
// ensure smart actions not called by default
- verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction(
- any(Context.class), any(String.class), any(String.class), anyBoolean());
+ verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction(any(Context.class),
+ any(String.class), any(String.class), anyBoolean(), any(Intent.class));
}
@Test
@@ -128,8 +129,8 @@
mDeleteScreenshotReceiver.onReceive(mContext, intent);
verify(mMockExecutor).execute(any(Runnable.class));
- verify(mMockScreenshotSmartActions).notifyScreenshotAction(
- mContext, testId, ACTION_TYPE_DELETE, false);
+ verify(mMockScreenshotSmartActions).notifyScreenshotAction(mContext, testId,
+ ACTION_TYPE_DELETE, false, null);
}
private static ContentValues getFakeContentValues() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
index 6f3a4a1..011e6b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Intent;
@@ -65,12 +66,14 @@
String testActionType = "testActionType";
mIntent.putExtra(EXTRA_ID, testId);
mIntent.putExtra(EXTRA_ACTION_TYPE, testActionType);
+ Intent intent = new Intent();
+ when(mMockPendingIntent.getIntent()).thenReturn(intent);
mSmartActionsReceiver.onReceive(mContext, mIntent);
verify(mMockPendingIntent).send(
eq(mContext), eq(0), isNull(), isNull(), isNull(), isNull(), any(Bundle.class));
verify(mMockScreenshotSmartActions).notifyScreenshotAction(
- mContext, testId, testActionType, true);
+ mContext, testId, testActionType, true, intent);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index b2487e8..b3d52b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -178,7 +178,7 @@
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
- @Mock private StatusBarIconController mStatusBarIconController;
+ @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private KeyguardIndicationController mKeyguardIndicationController;
@@ -356,7 +356,7 @@
mLightBarController,
mAutoHideController,
mKeyguardUpdateMonitor,
- mStatusBarIconController,
+ mStatusBarSignalPolicy,
mPulseExpansionHandler,
mNotificationWakeUpCoordinator,
mKeyguardBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index c244290..896e330 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone.ongoingcall
+import android.app.ActivityManager
+import android.app.IActivityManager
+import android.app.IUidObserver
import android.app.Notification
import android.app.PendingIntent
import android.app.Person
@@ -34,31 +37,46 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.*
import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.never
import org.mockito.Mockito.times
-import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+private const val CALL_UID = 900
+
+// A process state that represents the process being visible to the user.
+private const val PROC_STATE_VISIBLE = ActivityManager.PROCESS_STATE_TOP
+
+// A process state that represents the process being invisible to the user.
+private const val PROC_STATE_INVISIBLE = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class OngoingCallControllerTest : SysuiTestCase() {
+ private val clock = FakeSystemClock()
+ private val mainExecutor = FakeExecutor(clock)
+
private lateinit var controller: OngoingCallController
private lateinit var notifCollectionListener: NotifCollectionListener
@Mock private lateinit var mockOngoingCallListener: OngoingCallListener
@Mock private lateinit var mockActivityStarter: ActivityStarter
+ @Mock private lateinit var mockIActivityManager: IActivityManager
private lateinit var chipView: LinearLayout
@@ -76,7 +94,12 @@
val notificationCollection = mock(CommonNotifCollection::class.java)
controller = OngoingCallController(
- notificationCollection, featureFlags, FakeSystemClock(), mockActivityStarter)
+ notificationCollection,
+ featureFlags,
+ clock,
+ mockActivityStarter,
+ mainExecutor,
+ mockIActivityManager)
controller.init()
controller.addCallback(mockOngoingCallListener)
controller.setChipView(chipView)
@@ -84,34 +107,37 @@
val collectionListenerCaptor = ArgumentCaptor.forClass(NotifCollectionListener::class.java)
verify(notificationCollection).addCollectionListener(collectionListenerCaptor.capture())
notifCollectionListener = collectionListenerCaptor.value!!
+
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenReturn(PROC_STATE_INVISIBLE)
}
@Test
fun onEntryUpdated_isOngoingCallNotif_listenerNotifiedWithRightCallTime() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- verify(mockOngoingCallListener).onOngoingCallStarted(anyBoolean())
+ verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
@Test
fun onEntryUpdated_notOngoingCallNotif_listenerNotNotified() {
notifCollectionListener.onEntryUpdated(createNotCallNotifEntry())
- verify(mockOngoingCallListener, never()).onOngoingCallStarted(anyBoolean())
+ verify(mockOngoingCallListener, never()).onOngoingCallStateChanged(anyBoolean())
}
@Test
fun onEntryRemoved_ongoingCallNotif_listenerNotified() {
notifCollectionListener.onEntryRemoved(createOngoingCallNotifEntry(), REASON_USER_STOPPED)
- verify(mockOngoingCallListener).onOngoingCallEnded(anyBoolean())
+ verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
@Test
fun onEntryRemoved_notOngoingCallNotif_listenerNotNotified() {
notifCollectionListener.onEntryRemoved(createNotCallNotifEntry(), REASON_USER_STOPPED)
- verify(mockOngoingCallListener, never()).onOngoingCallEnded(anyBoolean())
+ verify(mockOngoingCallListener, never()).onOngoingCallStateChanged(anyBoolean())
}
@Test
@@ -120,13 +146,26 @@
}
@Test
- fun hasOngoingCall_ongoingCallNotifSentAndChipViewSet_returnsTrue() {
+ fun hasOngoingCall_ongoingCallNotifSentAndCallAppNotVisible_returnsTrue() {
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenReturn(PROC_STATE_INVISIBLE)
+
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
assertThat(controller.hasOngoingCall()).isTrue()
}
@Test
+ fun hasOngoingCall_ongoingCallNotifSentButCallAppVisible_returnsFalse() {
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenReturn(PROC_STATE_VISIBLE)
+
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ assertThat(controller.hasOngoingCall()).isFalse()
+ }
+
+ @Test
fun hasOngoingCall_ongoingCallNotifSentButInvalidChipView_returnsFalse() {
val invalidChipView = LinearLayout(context)
controller.setChipView(invalidChipView)
@@ -169,7 +208,52 @@
// Verify the listener was notified once for the initial call and again when the new view
// was set.
- verify(mockOngoingCallListener, times(2)).onOngoingCallStarted(anyBoolean())
+ verify(mockOngoingCallListener, times(2))
+ .onOngoingCallStateChanged(anyBoolean())
+ }
+
+ @Test
+ fun callProcessChangesToVisible_listenerNotified() {
+ // Start the call while the process is invisible.
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenReturn(PROC_STATE_INVISIBLE)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ val captor = ArgumentCaptor.forClass(IUidObserver.Stub::class.java)
+ verify(mockIActivityManager).registerUidObserver(
+ captor.capture(), any(), any(), nullable(String::class.java))
+ val uidObserver = captor.value
+
+ // Update the process to visible.
+ uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_VISIBLE, 0, 0)
+ mainExecutor.advanceClockToLast()
+ mainExecutor.runAllReady();
+
+ // Once for when the call was started, and another time when the process visibility changes.
+ verify(mockOngoingCallListener, times(2))
+ .onOngoingCallStateChanged(anyBoolean())
+ }
+
+ @Test
+ fun callProcessChangesToInvisible_listenerNotified() {
+ // Start the call while the process is visible.
+ `when`(mockIActivityManager.getUidProcessState(eq(CALL_UID), nullable(String::class.java)))
+ .thenReturn(PROC_STATE_VISIBLE)
+ notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+
+ val captor = ArgumentCaptor.forClass(IUidObserver.Stub::class.java)
+ verify(mockIActivityManager).registerUidObserver(
+ captor.capture(), any(), any(), nullable(String::class.java))
+ val uidObserver = captor.value
+
+ // Update the process to invisible.
+ uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_INVISIBLE, 0, 0)
+ mainExecutor.advanceClockToLast()
+ mainExecutor.runAllReady();
+
+ // Once for when the call was started, and another time when the process visibility changes.
+ verify(mockOngoingCallListener, times(2))
+ .onOngoingCallStateChanged(anyBoolean())
}
private fun createOngoingCallNotifEntry(): NotificationEntry {
@@ -179,6 +263,7 @@
val contentIntent = mock(PendingIntent::class.java)
`when`(contentIntent.intent).thenReturn(mock(Intent::class.java))
notificationEntryBuilder.modifyNotification(context).setContentIntent(contentIntent)
+ notificationEntryBuilder.setUid(CALL_UID)
return notificationEntryBuilder.build()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index f33c9e8..abc66db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -76,6 +76,7 @@
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.telephony.TelephonyListenerManager;
+import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -124,6 +125,7 @@
protected DeviceProvisionedListener mUserCallback;
protected Instrumentation mInstrumentation;
protected DemoModeController mDemoModeController;
+ protected CarrierConfigTracker mCarrierConfigTracker;
protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
protected int mSubId;
@@ -174,6 +176,7 @@
mMockBd = mock(BroadcastDispatcher.class);
mMockNsm = mock(NetworkScoreManager.class);
mMockSubDefaults = mock(SubscriptionDefaults.class);
+ mCarrierConfigTracker = mock(CarrierConfigTracker.class);
mNetCapabilities = new NetworkCapabilities();
when(mMockTm.isDataCapable()).thenReturn(true);
when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm);
@@ -231,7 +234,8 @@
mMockSubDefaults,
mMockProvisionController,
mMockBd,
- mDemoModeController);
+ mDemoModeController,
+ mCarrierConfigTracker);
setupNetworkController();
// Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -298,7 +302,8 @@
mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
- mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);
+ mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
+ mCarrierConfigTracker);
setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 6219faf..09554e717 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -21,6 +21,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.util.CarrierConfigTracker;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -111,7 +112,8 @@
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
- mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);
+ mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
+ mock(CarrierConfigTracker.class));
setupNetworkController();
setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 8d3e403..1e7801d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -41,6 +41,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
+import com.android.systemui.util.CarrierConfigTracker;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,7 +67,7 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController);
+ mDemoModeController, mock(CarrierConfigTracker.class));
setupNetworkController();
verifyLastMobileDataIndicators(false, -1, 0);
@@ -86,7 +87,7 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController);
+ mDemoModeController, mock(CarrierConfigTracker.class));
mNetworkController.registerListeners();
// Wait for the main looper to execute the previous command
@@ -154,7 +155,7 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController);
+ mDemoModeController, mock(CarrierConfigTracker.class));
setupNetworkController();
// No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index bfb98de..687ca60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -269,9 +269,9 @@
}
// Set the ImsType to be IMS_TYPE_WWAN
setImsType(1);
+ setupDefaultSignal();
for (int testStrength = 0;
testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) {
- setupDefaultSignal();
setLevel(testStrength);
verifyLastCallStrength(TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[testStrength]);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index d922d2b..3bb6e08 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1839,6 +1839,8 @@
// For a full update we replace the RemoteViews completely.
widget.views = views;
}
+ widget.views.setProviderInstanceId(UPDATE_COUNTER.get());
+
int memoryUsage;
if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
(widget.views != null) &&
@@ -1939,6 +1941,9 @@
|| widget.host.callbacks == null || widget.host.zombie) {
return;
}
+ if (updateViews != null) {
+ updateViews.setProviderInstanceId(requestId);
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = widget.host;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index ab3060a..dc8f84a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -33,7 +33,7 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
-import android.app.IOnProjectionStateChangeListener;
+import android.app.IOnProjectionStateChangedListener;
import android.app.IUiModeManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -181,7 +181,7 @@
private SparseArray<List<ProjectionHolder>> mProjectionHolders;
@GuardedBy("mLock")
@Nullable
- private SparseArray<RemoteCallbackList<IOnProjectionStateChangeListener>> mProjectionListeners;
+ private SparseArray<RemoteCallbackList<IOnProjectionStateChangedListener>> mProjectionListeners;
public UiModeManagerService(Context context) {
this(context, /* setupWizardComplete= */ false, /* tm= */ null, new Injector());
@@ -993,11 +993,11 @@
}
}
- public void addOnProjectionStateChangeListener(IOnProjectionStateChangeListener listener,
+ public void addOnProjectionStateChangedListener(IOnProjectionStateChangedListener listener,
@UiModeManager.ProjectionType int projectionType) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PROJECTION_STATE,
- "registerProjectionStateListener");
+ "addOnProjectionStateChangedListener");
if (projectionType == PROJECTION_TYPE_NONE) {
return;
}
@@ -1027,11 +1027,11 @@
}
- public void removeOnProjectionStateChangeListener(
- IOnProjectionStateChangeListener listener) {
+ public void removeOnProjectionStateChangedListener(
+ IOnProjectionStateChangedListener listener) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PROJECTION_STATE,
- "unregisterProjectionStateListener");
+ "removeOnProjectionStateChangedListener");
synchronized (mLock) {
if (mProjectionListeners != null) {
for (int i = 0; i < mProjectionListeners.size(); ++i) {
@@ -1191,7 +1191,7 @@
// Every listener that is affected must be called back with all the state they are
// listening for.
if ((changedProjectionType & listenerProjectionType) != 0) {
- RemoteCallbackList<IOnProjectionStateChangeListener> listeners =
+ RemoteCallbackList<IOnProjectionStateChangedListener> listeners =
mProjectionListeners.valueAt(i);
List<String> packageNames = new ArrayList<>();
@UiModeManager.ProjectionType int activeProjectionTypes =
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b261231..5700bb36 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -155,7 +155,6 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
-import com.android.server.notification.NotificationManagerInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -1978,17 +1977,6 @@
showNow = isLegacyApp && mAm.mConstants.mFlagFgsNotificationDeferralApiGated;
}
if (!showNow) {
- // did we already show it?
- showNow = r.mFgsNotificationShown;
- }
- if (!showNow) {
- // Is the notification already showing for any reason?
- final NotificationManagerInternal nmi =
- LocalServices.getService(NotificationManagerInternal.class);
- showNow = nmi.isNotificationShown(r.appInfo.packageName, null,
- r.foregroundId, UserHandle.getUserId(uid));
- }
- if (!showNow) {
// has the app forced deferral?
if (!r.foregroundNoti.isForegroundDisplayForceDeferred()) {
// is the notification such that it should show right away?
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index cc98abf..af3f658 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3418,6 +3418,11 @@
return;
}
+ if (app.getPid() == 0 && !app.isPendingStart()) {
+ // This process has been killed and its cleanup is done, don't proceed the LRU update.
+ return;
+ }
+
synchronized (mProcLock) {
updateLruProcessLSP(app, client, hasActivity, hasService);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 0314510..fb919fb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1659,13 +1659,31 @@
final UsageStatsManagerInternal usmi =
LocalServices.getService(UsageStatsManagerInternal.class);
if (usmi != null) {
+ // This method name is unfortunate. It elevates apps to a higher bucket, so it ideally
+ // should be called before we attempt to schedule the job (especially as EJ).
usmi.reportSyncScheduled(syncOperation.owningPackage,
UserHandle.getUserId(syncOperation.owningUid),
syncOperation.isAppStandbyExempted());
}
- getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
+ final JobInfo ji = b.build();
+ int result = getJobScheduler().scheduleAsPackage(ji, syncOperation.owningPackage,
syncOperation.target.userId, syncOperation.wakeLockName());
+ if (result == JobScheduler.RESULT_FAILURE && ji.isExpedited()) {
+ if (isLoggable) {
+ Slog.i(TAG, "Failed to schedule EJ for " + syncOperation.owningPackage
+ + ". Downgrading to regular");
+ }
+ syncOperation.scheduleEjAsRegularJob = true;
+ b.setExpedited(false).setExtras(syncOperation.toJobInfoExtras());
+ result = getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
+ syncOperation.target.userId, syncOperation.wakeLockName());
+ }
+ if (result == JobScheduler.RESULT_FAILURE) {
+ Slog.e(TAG, "Failed to schedule job for " + syncOperation.owningPackage);
+ // TODO: notify AppStandbyController that the sync isn't actually scheduled so the
+ // bucket doesn't stay elevated
+ }
}
/**
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c51571a..1c27c65 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.input;
+import static android.view.Surface.ROTATION_0;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -38,6 +40,7 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayViewport;
@@ -97,6 +100,7 @@
import android.view.InputEvent;
import android.view.InputMonitor;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.VerifiedInputEvent;
@@ -820,6 +824,28 @@
&& mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
+ if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
+ if (event instanceof MotionEvent) {
+ final Context dispCtx = getContextForDisplay(event.getDisplayId());
+ final Display display = dispCtx.getDisplay();
+ final int rotation = display.getRotation();
+ if (rotation != ROTATION_0) {
+ final MotionEvent motion = (MotionEvent) event;
+ // Injections are currently expected to be in the space of the injector (ie.
+ // usually assumed to be post-rotated). Thus we need to unrotate into raw
+ // input coordinates for dispatch.
+ final Point sz = new Point();
+ display.getRealSize(sz);
+ if ((rotation % 2) != 0) {
+ final int tmpX = sz.x;
+ sz.x = sz.y;
+ sz.y = tmpX;
+ }
+ motion.applyTransform(MotionEvent.createRotateMatrix(
+ (4 - rotation), sz.x, sz.y));
+ }
+ }
+ }
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index 2ffc62a..66b23c4 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -58,13 +58,17 @@
private static final int EVENT_LOCATION_ENABLED = 2;
private static final int EVENT_PROVIDER_ENABLED = 3;
private static final int EVENT_PROVIDER_MOCKED = 4;
- private static final int EVENT_PROVIDER_REGISTER_CLIENT = 5;
- private static final int EVENT_PROVIDER_UNREGISTER_CLIENT = 6;
- private static final int EVENT_PROVIDER_UPDATE_REQUEST = 7;
- private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 8;
- private static final int EVENT_PROVIDER_DELIVER_LOCATION = 9;
- private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 10;
- private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 11;
+ private static final int EVENT_PROVIDER_CLIENT_REGISTER = 5;
+ private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 6;
+ private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 7;
+ private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 8;
+ private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 9;
+ private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 10;
+ private static final int EVENT_PROVIDER_UPDATE_REQUEST = 11;
+ private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 12;
+ private static final int EVENT_PROVIDER_DELIVER_LOCATION = 13;
+ private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 14;
+ private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 15;
@GuardedBy("mAggregateStats")
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
@@ -126,13 +130,13 @@
/** Logs a new client registration for a location provider. */
public void logProviderClientRegistered(String provider, CallerIdentity identity,
LocationRequest request) {
- addLogEvent(EVENT_PROVIDER_REGISTER_CLIENT, provider, identity, request);
+ addLogEvent(EVENT_PROVIDER_CLIENT_REGISTER, provider, identity, request);
getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
}
/** Logs a client unregistration for a location provider. */
public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
- addLogEvent(EVENT_PROVIDER_UNREGISTER_CLIENT, provider, identity);
+ addLogEvent(EVENT_PROVIDER_CLIENT_UNREGISTER, provider, identity);
getAggregateStats(provider, identity).markRequestRemoved();
}
@@ -148,14 +152,34 @@
/** Logs a client for a location provider entering the foreground state. */
public void logProviderClientForeground(String provider, CallerIdentity identity) {
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_CLIENT_FOREGROUND, provider, identity);
+ }
getAggregateStats(provider, identity).markRequestForeground();
}
/** Logs a client for a location provider leaving the foreground state. */
public void logProviderClientBackground(String provider, CallerIdentity identity) {
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_CLIENT_BACKGROUND, provider, identity);
+ }
getAggregateStats(provider, identity).markRequestBackground();
}
+ /** Logs a client for a location provider entering the permitted state. */
+ public void logProviderClientPermitted(String provider, CallerIdentity identity) {
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_CLIENT_PERMITTED, provider, identity);
+ }
+ }
+
+ /** Logs a client for a location provider leaving the permitted state. */
+ public void logProviderClientUnpermitted(String provider, CallerIdentity identity) {
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_CLIENT_UNPERMITTED, provider, identity);
+ }
+ }
+
/** Logs a change to the provider request for a location provider. */
public void logProviderUpdateRequest(String provider, ProviderRequest request) {
addLogEvent(EVENT_PROVIDER_UPDATE_REQUEST, provider, request);
@@ -201,12 +225,24 @@
(Boolean) args[2]);
case EVENT_PROVIDER_MOCKED:
return new ProviderMockedEvent(timeDelta, (String) args[0], (Boolean) args[1]);
- case EVENT_PROVIDER_REGISTER_CLIENT:
- return new ProviderRegisterEvent(timeDelta, (String) args[0], true,
+ case EVENT_PROVIDER_CLIENT_REGISTER:
+ return new ProviderClientRegisterEvent(timeDelta, (String) args[0], true,
(CallerIdentity) args[1], (LocationRequest) args[2]);
- case EVENT_PROVIDER_UNREGISTER_CLIENT:
- return new ProviderRegisterEvent(timeDelta, (String) args[0], false,
+ case EVENT_PROVIDER_CLIENT_UNREGISTER:
+ return new ProviderClientRegisterEvent(timeDelta, (String) args[0], false,
(CallerIdentity) args[1], null);
+ case EVENT_PROVIDER_CLIENT_FOREGROUND:
+ return new ProviderClientForegroundEvent(timeDelta, (String) args[0], true,
+ (CallerIdentity) args[1]);
+ case EVENT_PROVIDER_CLIENT_BACKGROUND:
+ return new ProviderClientForegroundEvent(timeDelta, (String) args[0], false,
+ (CallerIdentity) args[1]);
+ case EVENT_PROVIDER_CLIENT_PERMITTED:
+ return new ProviderClientPermittedEvent(timeDelta, (String) args[0], true,
+ (CallerIdentity) args[1]);
+ case EVENT_PROVIDER_CLIENT_UNPERMITTED:
+ return new ProviderClientPermittedEvent(timeDelta, (String) args[0], false,
+ (CallerIdentity) args[1]);
case EVENT_PROVIDER_UPDATE_REQUEST:
return new ProviderUpdateEvent(timeDelta, (String) args[0],
(ProviderRequest) args[1]);
@@ -279,13 +315,13 @@
}
}
- private static final class ProviderRegisterEvent extends ProviderEvent {
+ private static final class ProviderClientRegisterEvent extends ProviderEvent {
private final boolean mRegistered;
private final CallerIdentity mIdentity;
@Nullable private final LocationRequest mLocationRequest;
- ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
+ ProviderClientRegisterEvent(long timeDelta, String provider, boolean registered,
CallerIdentity identity, @Nullable LocationRequest locationRequest) {
super(timeDelta, provider);
mRegistered = registered;
@@ -296,14 +332,52 @@
@Override
public String getLogString() {
if (mRegistered) {
- return mProvider + " provider " + "+registration " + mIdentity + " -> "
+ return mProvider + " provider +registration " + mIdentity + " -> "
+ mLocationRequest;
} else {
- return mProvider + " provider " + "-registration " + mIdentity;
+ return mProvider + " provider -registration " + mIdentity;
}
}
}
+ private static final class ProviderClientForegroundEvent extends ProviderEvent {
+
+ private final boolean mForeground;
+ private final CallerIdentity mIdentity;
+
+ ProviderClientForegroundEvent(long timeDelta, String provider, boolean foreground,
+ CallerIdentity identity) {
+ super(timeDelta, provider);
+ mForeground = foreground;
+ mIdentity = identity;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider client " + mIdentity + " -> "
+ + (mForeground ? "foreground" : "background");
+ }
+ }
+
+ private static final class ProviderClientPermittedEvent extends ProviderEvent {
+
+ private final boolean mPermitted;
+ private final CallerIdentity mIdentity;
+
+ ProviderClientPermittedEvent(long timeDelta, String provider, boolean permitted,
+ CallerIdentity identity) {
+ super(timeDelta, provider);
+ mPermitted = permitted;
+ mIdentity = identity;
+ }
+
+ @Override
+ public String getLogString() {
+ return mProvider + " provider client " + mIdentity + " -> "
+ + (mPermitted ? "permitted" : "unpermitted");
+ }
+ }
+
private static final class ProviderUpdateEvent extends ProviderEvent {
private final ProviderRequest mRequest;
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 4b772f2..9474f5d 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -523,6 +523,13 @@
}
mPermitted = permitted;
+
+ if (mForeground) {
+ EVENT_LOG.logProviderClientPermitted(mName, getIdentity());
+ } else {
+ EVENT_LOG.logProviderClientUnpermitted(mName, getIdentity());
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index b9822fcb..d285c43 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -258,16 +258,16 @@
if (mActiveAudioUids.size() > 0
&& !mActiveAudioUids.contains(mSortedAudioPlaybackClientUids.get(0))) {
int firstActiveUid = -1;
- int firatActiveUidIndex = -1;
+ int firstActiveUidIndex = -1;
for (int i = 1; i < mSortedAudioPlaybackClientUids.size(); ++i) {
int uid = mSortedAudioPlaybackClientUids.get(i);
if (mActiveAudioUids.contains(uid)) {
- firatActiveUidIndex = i;
+ firstActiveUidIndex = i;
firstActiveUid = uid;
break;
}
}
- for (int i = firatActiveUidIndex; i > 0; --i) {
+ for (int i = firstActiveUidIndex; i > 0; --i) {
mSortedAudioPlaybackClientUids.set(i,
mSortedAudioPlaybackClientUids.get(i - 1));
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 384bc99..9f02c3c 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -907,6 +907,8 @@
mActiveBluetoothDevice = btDevice;
mGlobalBluetoothA2dpOn = btDevice != null;
if (wasA2dpOn != mGlobalBluetoothA2dpOn) {
+ Slog.d(TAG, "GlobalBluetoothA2dpOn is changed to '"
+ + mGlobalBluetoothA2dpOn + "'");
UserRecord userRecord = mUserRecords.get(mCurrentUserId);
if (userRecord != null) {
for (ClientRecord cr : userRecord.mClientRecords) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 0528b95..dc9839c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -30,9 +30,6 @@
void cancelNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, int userId);
- /** is the given notification currently showing? */
- boolean isNotificationShown(String pkg, String tag, int notificationId, int userId);
-
void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId);
void onConversationRemoved(String pkg, int uid, Set<String> shortcuts);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 44169a5..53e3a0e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6054,13 +6054,6 @@
}
@Override
- public boolean isNotificationShown(String pkg, String tag, int notificationId, int userId) {
- synchronized (mNotificationLock) {
- return findNotificationLocked(pkg, tag, notificationId, userId) != null;
- }
- }
-
- @Override
public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
int userId) {
checkCallerIsSystem();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 27f5350..0a65c23 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -379,6 +379,7 @@
private DisplayFoldController mDisplayFoldController;
AppOpsManager mAppOpsManager;
PackageManager mPackageManager;
+ SideFpsEventHandler mSideFpsEventHandler;
private boolean mHasFeatureAuto;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
@@ -928,6 +929,11 @@
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !beganFromNonInteractive) {
+ if (mSideFpsEventHandler.onSinglePressDetected(eventTime)) {
+ Slog.i(TAG, "Suppressing power key because the user is interacting with the "
+ + "fingerprint sensor");
+ return;
+ }
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
@@ -1803,6 +1809,7 @@
});
initKeyCombinationRules();
initSingleKeyGestureRules();
+ mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
}
private void initKeyCombinationRules() {
@@ -4668,6 +4675,7 @@
mKeyguardDelegate.onBootCompleted();
}
}
+ mSideFpsEventHandler.onFingerprintSensorReady();
startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
diff --git a/services/core/java/com/android/server/policy/SideFpsEventHandler.java b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
new file mode 100644
index 0000000..7c0005c
--- /dev/null
+++ b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
+import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
+
+import android.annotation.NonNull;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintStateListener;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Defines behavior for handling interactions between power button events and
+ * fingerprint-related operations, for devices where the fingerprint sensor (side fps)
+ * lives on the power button.
+ */
+public class SideFpsEventHandler {
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final PowerManager mPowerManager;
+ @NonNull private final AtomicBoolean mIsSideFps;
+ @NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
+
+ private @FingerprintStateListener.State int mFingerprintState;
+
+ SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
+ mContext = context;
+ mHandler = handler;
+ mPowerManager = powerManager;
+ mFingerprintState = STATE_IDLE;
+ mIsSideFps = new AtomicBoolean(false);
+ mSideFpsEventHandlerReady = new AtomicBoolean(false);
+ }
+
+ /**
+ * Called from {@link PhoneWindowManager} after power button is pressed. Checks fingerprint
+ * sensor state and if mFingerprintState = STATE_ENROLLING, displays a dialog confirming intent
+ * to turn screen off. If confirmed, the device goes to sleep, and if canceled, the dialog is
+ * dismissed.
+ * @param eventTime powerPress event time
+ * @return true if powerPress was consumed, false otherwise
+ */
+ public boolean onSinglePressDetected(long eventTime) {
+ if (!mSideFpsEventHandlerReady.get() || !mIsSideFps.get()
+ || mFingerprintState != STATE_ENROLLING) {
+ return false;
+ }
+ mHandler.post(() -> {
+ Dialog confirmScreenOffDialog = new AlertDialog.Builder(mContext)
+ .setTitle(R.string.fp_enrollment_powerbutton_intent_title)
+ .setMessage(R.string.fp_enrollment_powerbutton_intent_message)
+ .setPositiveButton(
+ R.string.fp_enrollment_powerbutton_intent_positive_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ mPowerManager.goToSleep(
+ eventTime,
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ 0 /* flags */
+ );
+ }
+ })
+ .setNegativeButton(
+ R.string.fp_enrollment_powerbutton_intent_negative_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ })
+ .setCancelable(false)
+ .create();
+ confirmScreenOffDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+ confirmScreenOffDialog.show();
+ });
+ return true;
+ }
+
+ /**
+ * Awaits notification from PhoneWindowManager that fingerprint service is ready
+ * to send updates about power button fps sensor state. Then configures a
+ * FingerprintStateListener to receive and record updates to fps state, and
+ * registers the FingerprintStateListener in FingerprintManager.
+ */
+ public void onFingerprintSensorReady() {
+ final PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) return;
+ FingerprintManager fingerprintManager =
+ mContext.getSystemService(FingerprintManager.class);
+ fingerprintManager.addAuthenticatorsRegisteredCallback(
+ new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
+ @Override
+ public void onAllAuthenticatorsRegistered(
+ List<FingerprintSensorPropertiesInternal> sensors) {
+ mIsSideFps.set(fingerprintManager.isPowerbuttonFps());
+ FingerprintStateListener fingerprintStateListener =
+ new FingerprintStateListener() {
+ @Override
+ public void onStateChanged(
+ @FingerprintStateListener.State int newState) {
+ mFingerprintState = newState;
+ }
+ };
+ fingerprintManager.registerFingerprintStateListener(
+ fingerprintStateListener);
+ mSideFpsEventHandlerReady.set(true);
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index 03584b9..68e7bdb 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -256,7 +256,7 @@
private final ContentResolver mContentResolver;
private final BatterySavingStats mBatterySavingStats;
- private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener =
+ private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener =
(t, pkgs) -> mAutomotiveProjectionActive.update(!pkgs.isEmpty());
@GuardedBy("mLock")
@@ -292,8 +292,8 @@
mAccessibilityEnabled.initialize(acm.isEnabled());
UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
- uiModeManager.addOnProjectionStateChangeListener(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE,
- mContext.getMainExecutor(), mOnProjectionStateChangeListener);
+ uiModeManager.addOnProjectionStateChangedListener(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE,
+ mContext.getMainExecutor(), mOnProjectionStateChangedListener);
mAutomotiveProjectionActive.initialize(
uiModeManager.getActiveProjectionTypes() != UiModeManager.PROJECTION_TYPE_NONE);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 203214d..30f69dd79 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2861,6 +2861,10 @@
mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
}
+ boolean onSystemUiSettingsChanged() {
+ return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId);
+ }
+
/**
* Request a screenshot be taken.
*
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index b94bc5b..747d365 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -148,6 +148,15 @@
}
}
+ boolean onSettingChanged(int currentUserId) {
+ final boolean changed = loadSetting(currentUserId, mContext);
+ // Remove the window if the setting changes to be confirmed.
+ if (changed && sConfirmed) {
+ mHandler.sendEmptyMessage(H.HIDE);
+ }
+ return changed;
+ }
+
void immersiveModeChangedLw(int rootDisplayAreaId, boolean isImmersiveMode,
boolean userSetupComplete, boolean navBarEmpty) {
mHandler.removeMessages(H.SHOW);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1657a13..d43a763 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -818,7 +818,7 @@
}
if (mImmersiveModeConfirmationsUri.equals(uri) || mPolicyControlUri.equals(uri)) {
- updateSystemUiSettings();
+ updateSystemUiSettings(true /* handleChange */);
return;
}
@@ -874,17 +874,22 @@
}
void loadSettings() {
- updateSystemUiSettings();
+ updateSystemUiSettings(false /* handleChange */);
updatePointerLocation();
}
- void updateSystemUiSettings() {
- boolean changed;
+ void updateSystemUiSettings(boolean handleChange) {
synchronized (mGlobalLock) {
- changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext);
- }
- if (changed) {
- updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */);
+ boolean changed = false;
+ if (handleChange) {
+ changed = getDefaultDisplayContentLocked().getDisplayPolicy()
+ .onSystemUiSettingsChanged();
+ } else {
+ ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext);
+ }
+ if (changed) {
+ mWindowPlacerLocked.requestTraversal();
+ }
}
}
@@ -2990,7 +2995,7 @@
@Override
public void onUserSwitched() {
- mSettingsObserver.updateSystemUiSettings();
+ mSettingsObserver.updateSystemUiSettings(true /* handleChange */);
synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index d913d4e..7189fb4 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -1149,11 +1149,11 @@
if (conversationInfo == null) {
return;
}
+ if (DEBUG) Log.d(TAG, "Last event from notification: " + sbn.getPostTime());
ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
.setLastEventTimestamp(sbn.getPostTime())
.setParentNotificationChannelId(sbn.getNotification().getChannelId())
.build();
- // Don't update listeners on notifications posted.
packageData.getConversationStore().addOrUpdate(updated);
EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
@@ -1186,9 +1186,19 @@
if (reason != REASON_CLICK || packageData == null) {
return;
}
+ long currentTime = System.currentTimeMillis();
+ ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+ if (conversationInfo == null) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Last event from notification removed: " + currentTime);
+ ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
+ .setLastEventTimestamp(currentTime)
+ .build();
+ packageData.getConversationStore().addOrUpdate(updated);
+
EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
- long currentTime = System.currentTimeMillis();
eventHistory.addEvent(new Event(currentTime, Event.TYPE_NOTIFICATION_OPENED));
}
@@ -1265,6 +1275,7 @@
public void onEvent(PackageData packageData, ConversationInfo conversationInfo,
Event event) {
if (event.getType() == Event.TYPE_IN_APP_CONVERSATION) {
+ if (DEBUG) Log.d(TAG, "Last event from in-app: " + event.getTimestamp());
ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
.setLastEventTimestamp(event.getTimestamp())
.build();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 6468790..029930a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -68,7 +68,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -475,7 +474,6 @@
expectedRegular.add(thr);
expectedRegular.add(two);
expectedRegular.add(one);
- expectedEJ.add(fiv); // EJ list should be unaffected
expectedEJ.add(fou);
expectedEJ.add(one);
mQuotaController.saveTimingSession(0, "com.android.test", fiv, false);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 6c1e915b..b112f3fc 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -693,7 +693,6 @@
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
listenerService.onNotificationPosted(mStatusBarNotification);
-
ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
TEST_SHORTCUT_ID);
@@ -1361,6 +1360,27 @@
}
@Test
+ public void testNotificationRemoved() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ NotificationListenerService.REASON_CANCEL);
+
+ ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+ .getConversationStore()
+ .getConversation(TEST_SHORTCUT_ID);
+ assertEquals(conversationInfo.getLastEventTimestamp(), System.currentTimeMillis());
+ }
+
+ @Test
public void testRemoveRecentConversation() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 81c237b..4b3771b 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -55,7 +55,7 @@
import android.Manifest;
import android.app.AlarmManager;
-import android.app.IOnProjectionStateChangeListener;
+import android.app.IOnProjectionStateChangedListener;
import android.app.IUiModeManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -669,46 +669,46 @@
}
@Test
- public void addOnProjectionStateChangeListener_enforcesReadProjStatePermission() {
+ public void addOnProjectionStateChangedListener_enforcesReadProjStatePermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
- assertThrows(SecurityException.class, () -> mService.addOnProjectionStateChangeListener(
+ assertThrows(SecurityException.class, () -> mService.addOnProjectionStateChangedListener(
listener, PROJECTION_TYPE_ALL));
}
@Test
- public void addOnProjectionStateChangeListener_callsListenerIfProjectionActive()
+ public void addOnProjectionStateChangedListener_callsListenerIfProjectionActive()
throws Exception {
when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
when(listener.asBinder()).thenReturn(mBinder); // Any binder will do
- mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
eq(List.of(PACKAGE_NAME)));
}
@Test
- public void removeOnProjectionStateChangeListener_enforcesReadProjStatePermission() {
+ public void removeOnProjectionStateChangedListener_enforcesReadProjStatePermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
- assertThrows(SecurityException.class, () -> mService.removeOnProjectionStateChangeListener(
+ assertThrows(SecurityException.class, () -> mService.removeOnProjectionStateChangedListener(
listener));
}
@Test
- public void removeOnProjectionStateChangeListener() throws Exception {
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ public void removeOnProjectionStateChangedListener() throws Exception {
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
- mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
- mService.removeOnProjectionStateChangeListener(listener);
+ mService.removeOnProjectionStateChangedListener(listener);
// Now set automotive projection, should not call back.
when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
@@ -716,10 +716,10 @@
}
@Test
- public void projectionStateChangeListener_calledWhenStateChanges() throws Exception {
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ public void projectionStateChangedListener_calledWhenStateChanges() throws Exception {
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
- mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
// No calls initially, no projection state set.
@@ -748,19 +748,19 @@
}
@Test
- public void projectionStateChangeListener_calledForAnyRelevantStateChange() throws Exception {
+ public void projectionStateChangedListener_calledForAnyRelevantStateChange() throws Exception {
int fakeProjectionType = 0x0002;
int otherFakeProjectionType = 0x0004;
String otherPackageName = "Internet Arms";
when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
when(mPackageManager.getPackageUid(otherPackageName, 0))
.thenReturn(TestInjector.CALLING_UID);
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
- IOnProjectionStateChangeListener listener2 = mock(IOnProjectionStateChangeListener.class);
+ IOnProjectionStateChangedListener listener2 = mock(IOnProjectionStateChangedListener.class);
when(listener2.asBinder()).thenReturn(mBinder); // Any binder will do.
- mService.addOnProjectionStateChangeListener(listener, fakeProjectionType);
- mService.addOnProjectionStateChangeListener(listener2,
+ mService.addOnProjectionStateChangedListener(listener, fakeProjectionType);
+ mService.addOnProjectionStateChangedListener(listener2,
fakeProjectionType | otherFakeProjectionType);
verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
verify(listener2, atLeastOnce()).asBinder(); // Called twice during register.
@@ -795,11 +795,11 @@
}
@Test
- public void projectionStateChangeListener_unregisteredOnDeath() throws Exception {
- IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ public void projectionStateChangedListener_unregisteredOnDeath() throws Exception {
+ IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
IBinder listenerBinder = mock(IBinder.class);
when(listener.asBinder()).thenReturn(listenerBinder);
- mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ mService.addOnProjectionStateChangedListener(listener, PROJECTION_TYPE_ALL);
ArgumentCaptor<IBinder.DeathRecipient> listenerDeathRecipient = ArgumentCaptor.forClass(
IBinder.DeathRecipient.class);
verify(listenerBinder).linkToDeath(listenerDeathRecipient.capture(), anyInt());
diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
index a9e1a8f..bf49f3c 100644
--- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
+++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
@@ -483,7 +483,16 @@
// check to see if these are recognized numbers, and use shortcuts if we can.
TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- if (tm.isEmergencyNumber(number)) {
+ boolean isEmergencyNumber = false;
+ try {
+ isEmergencyNumber = tm.isEmergencyNumber(number);
+ } catch (IllegalStateException ise) {
+ // Ignore the exception that Telephony is not up. Use PhoneNumberUtils API now.
+ // Ideally the PhoneNumberUtils API needs to be removed once the
+ // telphony service not up issue can be fixed (b/187412989)
+ isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(context, number);
+ }
+ if (isEmergencyNumber) {
cw.event = EVENT_EMERGENCY_NUMBER;
} else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index d361db2..4d81b5e 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -263,7 +263,7 @@
return true;
}
return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
- context, subId, callingPackage, callingFeatureId, message, true);
+ context, subId, callingPackage, callingFeatureId, message, true, true);
}
/**
@@ -286,14 +286,28 @@
*/
public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
String callingPackage, @Nullable String callingFeatureId, String message) {
+ return checkCallingOrSelfReadSubscriberIdentifiers(context, subId, callingPackage,
+ callingFeatureId, message, true);
+ }
+
+ /**
+ * Same as {@link #checkCallingOrSelfReadSubscriberIdentifiers(Context, int, String, String,
+ * String)} except this allows an additional parameter reportFailure. Caller may not want to
+ * report a failure when this is an internal/intermediate check, for example,
+ * SubscriptionController calls this with an INVALID_SUBID to check if caller has the required
+ * permissions to bypass carrier privilege checks.
+ * @param reportFailure Indicates if failure should be reported.
+ */
+ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
+ String callingPackage, @Nullable String callingFeatureId, String message,
+ boolean reportFailure) {
if (checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, callingPackage,
callingFeatureId, message)) {
return true;
}
return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
- context, subId, callingPackage, callingFeatureId, message, false);
+ context, subId, callingPackage, callingFeatureId, message, false, reportFailure);
}
-
/**
* Checks whether the app with the given pid/uid can read device identifiers.
*
@@ -314,7 +328,7 @@
*/
private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
- String message, boolean allowCarrierPrivilegeOnAnySub) {
+ String message, boolean allowCarrierPrivilegeOnAnySub, boolean reportFailure) {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
@@ -334,8 +348,12 @@
return true;
}
- return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
- message);
+ if (reportFailure) {
+ return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+ message);
+ } else {
+ return false;
+ }
}
/**
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index 6867c86..fd8d8a7 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -357,9 +357,9 @@
/**
* Check whether Rcs Volte single registration is supported by the config.
*/
- public boolean isRcsVolteSingleRegistrationSupported() {
- return getBoolean(PARM_SINGLE_REGISTRATION, false)
- || getInteger(PARM_SINGLE_REGISTRATION, 0) != 0;
+ public boolean isRcsVolteSingleRegistrationSupported(boolean isRoaming) {
+ int val = getInteger(PARM_SINGLE_REGISTRATION, 1);
+ return isRoaming ? val == 1 : val > 0;
}
@Override
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
index 79410cf..d925541 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RuntimeShader;
@@ -48,6 +49,7 @@
static class RippleView extends View {
static final int DURATION = 1000;
static final int MAX_RADIUS = 250;
+ private final int mColor = Color.RED;
private boolean mToggle = false;
ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
@@ -104,7 +106,7 @@
Paint p = new Paint();
p.setAntiAlias(true);
- p.setColor(0xFFFF0000);
+ p.setColor(mColor);
mPaint = CanvasProperty.createPaint(p);
mRuntimeShader = new RuntimeShader(sSkSL, false);
@@ -118,7 +120,7 @@
if (canvas.isHardwareAccelerated()) {
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
- mRuntimeShader);
+ mColor, mRuntimeShader);
}
}
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
index 53eab68..c8a85de 100644
--- a/tests/UiBench/res/layout/recycler_view.xml
+++ b/tests/UiBench/res/layout/recycler_view.xml
@@ -17,5 +17,6 @@
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
+ android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index a44ad1e..eff6658 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -61,7 +61,6 @@
private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
NetworkMonitor.Dependencies() {
override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
- override fun sendNetworkConditionsBroadcast(context: Context, broadcast: Intent) = Unit
}
private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
@@ -98,4 +97,4 @@
cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
}
}
-}
\ No newline at end of file
+}