Merge "Ensure that the blocking helper will run" into pi-dev
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 61ae6e7..3a3a708 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -20,7 +20,7 @@
Landroid/app/AppOpsManager$PackageOps;->getPackageName()Ljava/lang/String;
Landroid/app/AppOpsManager$PackageOps;->getUid()I
Landroid/app/IActivityController$Stub;-><init>()V
-Landroid/app/IActivityManager;->cancelRecentsAnimation()V
+Landroid/app/IActivityManager;->cancelRecentsAnimation(Z)V
Landroid/app/IActivityManager;->cancelTaskWindowTransition(I)V
Landroid/app/IActivityManager;->closeSystemDialogs(Ljava/lang/String;)V
Landroid/app/IActivityManager;->getCurrentUser()Landroid/content/pm/UserInfo;
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e1a02fa..919f714 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -450,7 +450,7 @@
in Intent intent, in String resolvedType, in Bundle options, int userId);
void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
in IRecentsAnimationRunner recentsAnimationRunner);
- void cancelRecentsAnimation();
+ void cancelRecentsAnimation(boolean restoreHomeStackPosition);
int startActivityFromRecents(int taskId, in Bundle options);
Bundle getActivityOptions(in IBinder token);
List<IBinder> getAppTasks(in String callingPackage);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ddd0656..5067e19 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -73,6 +73,7 @@
ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getDeletedChannelCount(String pkg, int uid);
+ int getBlockedChannelCount(String pkg, int uid);
void deleteNotificationChannelGroup(String pkg, String channelGroupId);
NotificationChannelGroup getNotificationChannelGroup(String pkg, String channelGroupId);
ParceledListSlice getNotificationChannelGroups(String pkg);
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 89684ca..c0b40c8 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -59,4 +59,9 @@
* taken.
*/
void setAnimationTargetsBehindSystemBars(boolean behindSystemBars);
+
+ /**
+ * Informs the system that the primary split-screen stack should be minimized.
+ */
+ void setSplitScreenMinimized(boolean minimized);
}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
new file mode 100644
index 0000000..ed42e2e
--- /dev/null
+++ b/core/proto/OWNERS
@@ -0,0 +1,13 @@
+# Be sure you are familiar with proto when you modify this directory.
+
+# Metrics
+bookatz@google.com
+cjyu@google.com
+jinyithu@google.com
+joeo@google.com
+kwekua@google.com
+singhtejinder@google.com
+
+# Frameworks
+ogunwale@google.com
+jjaggi@google.com
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eebf581..02d6c9fc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1205,7 +1205,6 @@
<java-symbol type="string" name="ssl_ca_cert_noti_by_administrator" />
<java-symbol type="string" name="ssl_ca_cert_noti_managed" />
<java-symbol type="string" name="work_profile_deleted" />
- <java-symbol type="string" name="work_profile_deleted_description" />
<java-symbol type="string" name="work_profile_deleted_details" />
<java-symbol type="string" name="work_profile_deleted_description_dpm_wipe" />
<java-symbol type="string" name="work_profile_deleted_reason_maximum_password_failure" />
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index fa3f99a..12768817 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -89,6 +89,10 @@
ProviderProperties getProviderProperties(String provider);
String getNetworkProviderPackage();
+ boolean isProviderEnabledForUser(String provider, int userId);
+ boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
+ boolean isLocationEnabledForUser(int userId);
+ void setLocationEnabledForUser(boolean enabled, int userId);
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
void removeTestProvider(String provider, String opPackageName);
void setTestProviderLocation(String provider, in Location loc, String opPackageName);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index a523958..38286a3 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1249,40 +1249,11 @@
@SystemApi
@RequiresPermission(WRITE_SECURE_SETTINGS)
public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
- final List<String> allProvidersList = getAllProviders();
- // Update all providers on device plus gps and network provider when disabling location.
- Set<String> allProvidersSet = new ArraySet<>(allProvidersList.size() + 2);
- allProvidersSet.addAll(allProvidersList);
- // When disabling location, disable gps and network provider that could have been enabled by
- // location mode api.
- if (enabled == false) {
- allProvidersSet.add(GPS_PROVIDER);
- allProvidersSet.add(NETWORK_PROVIDER);
+ try {
+ mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- if (allProvidersSet.isEmpty()) {
- return;
- }
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- final String prefix = enabled ? "+" : "-";
- StringBuilder locationProvidersAllowed = new StringBuilder();
- for (String provider : allProvidersSet) {
- checkProvider(provider);
- if (provider.equals(PASSIVE_PROVIDER)) {
- continue;
- }
- locationProvidersAllowed.append(prefix);
- locationProvidersAllowed.append(provider);
- locationProvidersAllowed.append(",");
- }
- // Remove the trailing comma
- locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- locationProvidersAllowed.toString(),
- userHandle.getIdentifier());
}
/**
@@ -1295,22 +1266,11 @@
*/
@SystemApi
public boolean isLocationEnabledForUser(UserHandle userHandle) {
- final String allowedProviders = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- userHandle.getIdentifier());
- if (allowedProviders == null) {
- return false;
+ try {
+ return mService.isLocationEnabledForUser(userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- final List<String> providerList = Arrays.asList(allowedProviders.split(","));
- for(String provider : getAllProviders()) {
- if (provider.equals(PASSIVE_PROVIDER)) {
- continue;
- }
- if (providerList.contains(provider)) {
- return true;
- }
- }
- return false;
}
/**
@@ -1362,9 +1322,12 @@
@SystemApi
public boolean isProviderEnabledForUser(String provider, UserHandle userHandle) {
checkProvider(provider);
- String allowedProviders = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userHandle.getIdentifier());
- return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
+
+ try {
+ return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -1383,16 +1346,13 @@
public boolean setProviderEnabledForUser(
String provider, boolean enabled, UserHandle userHandle) {
checkProvider(provider);
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- if (enabled) {
- provider = "+" + provider;
- } else {
- provider = "-" + provider;
+
+ try {
+ return mService.setProviderEnabledForUser(
+ provider, enabled, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, userHandle.getIdentifier());
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 1aad27f..6aa2754 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -258,9 +258,9 @@
/**
* Cancels the remote recents animation started from {@link #startRecentsActivity}.
*/
- public void cancelRecentsAnimation() {
+ public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
try {
- ActivityManager.getService().cancelRecentsAnimation();
+ ActivityManager.getService().cancelRecentsAnimation(restoreHomeStackPosition);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 79c1cb1..bff0d9b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -17,10 +17,27 @@
package com.android.systemui.shared.system;
import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import sun.misc.Resource;
+
public class NavigationBarCompat {
+ /**
+ * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
+ * home button press/long press over are ignored and will start to drag when exceeded and the
+ * touch slop is when the respected operation will occur when exceeded. Touch slop must be
+ * larger than the drag slop.
+ */
+ public static final int QUICK_STEP_DRAG_SLOP_PX = convertDpToPixel(10);
+ public static final int QUICK_SCRUB_DRAG_SLOP_PX = convertDpToPixel(20);
+ public static final int QUICK_STEP_TOUCH_SLOP_PX = convertDpToPixel(40);
+ public static final int QUICK_SCRUB_TOUCH_SLOP_PX = convertDpToPixel(35);
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
public @interface HitTarget{}
@@ -42,7 +59,6 @@
* Interaction type: whether the gesture to swipe up from the navigation bar will trigger
* launcher to show overview
*/
-
public static final int FLAG_DISABLE_SWIPE_UP = 0x1;
/**
* Interaction type: enable quick scrub interaction on the home button
@@ -58,4 +74,8 @@
* Interaction type: show/hide the back button while this service is connected to launcher
*/
public static final int FLAG_HIDE_BACK_BUTTON = 0x8;
+
+ private static int convertDpToPixel(float dp){
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 5fa6c79..80e226d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -61,6 +61,14 @@
}
}
+ public void setSplitScreenMinimized(boolean minimized) {
+ try {
+ mAnimationController.setSplitScreenMinimized(minimized);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set minimize dock", e);
+ }
+ }
+
public void finish(boolean toHome) {
try {
mAnimationController.finish(toHome);
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 5a2263c..ae6ee2a 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -73,7 +73,7 @@
void onAppOpChanged(int code, int uid, String packageName, boolean active);
/**
- * Gets active app ops for this user and package.
+ * Gets active app ops for this user and package
*/
@Nullable ArraySet<Integer> getAppOps(int userId, String packageName);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index e18ac74..cdf4ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -16,6 +16,9 @@
package com.android.systemui.classifier;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayList;
@@ -49,13 +52,18 @@
public class AnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+ public static final boolean VERBOSE = SystemProperties.getBoolean("debug.falsing_log.ang",
+ Build.IS_DEBUGGABLE);
+
+ private static String TAG = "ANG";
+
public AnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@Override
public String getTag() {
- return "ANG";
+ return TAG;
}
@Override
@@ -170,18 +178,31 @@
public float getAnglesVariance() {
float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesVariance: (first pass) " + anglesVariance);
+ FalsingLog.i(TAG, " - mFirstLength=" + mFirstLength);
+ FalsingLog.i(TAG, " - mLength=" + mLength);
+ }
if (mFirstLength < mLength / 2f) {
anglesVariance = Math.min(anglesVariance, mFirstAngleVariance
+ getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount));
+ if (VERBOSE) FalsingLog.i(TAG, "getAnglesVariance: (second pass) " + anglesVariance);
}
return anglesVariance;
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
+ if (VERBOSE) FalsingLog.i(TAG, "getAnglesPercentage: count==0, result=1");
return 1.0f;
}
- return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
+ final float result = (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesPercentage: left=" + mLeftAngles + " right="
+ + mRightAngles + " straight=" + mStraightAngles + " count=" + mAnglesCount
+ + " result=" + result);
+ }
+ return result;
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 6883dd0..5f6c1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -20,8 +20,6 @@
public static float evaluate(float value, int type) {
final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
- if (value > 0.05) evaluation++;
- if (value > 0.10) evaluation++;
if (value > 0.20) evaluation++;
if (value > 0.40 && !secureUnlock) evaluation++;
if (value > 0.80 && !secureUnlock) evaluation++;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index 6df72b1..66f0cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
+import android.os.Build;
+import android.os.SystemProperties;
import android.view.MotionEvent;
import java.util.ArrayList;
@@ -34,6 +36,10 @@
* should be in this interval.
*/
public class SpeedAnglesClassifier extends StrokeClassifier {
+ public static final boolean VERBOSE = SystemProperties.getBoolean("debug.falsing_log.spd_ang",
+ Build.IS_DEBUGGABLE);
+ public static final String TAG = "SPD_ANG";
+
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
public SpeedAnglesClassifier(ClassifierData classifierData) {
@@ -42,7 +48,7 @@
@Override
public String getTag() {
- return "SPD_ANG";
+ return TAG;
}
@Override
@@ -135,14 +141,24 @@
}
public float getAnglesVariance() {
- return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+ final float v = mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesVariance: sum^2=" + mSumSquares
+ + " count=" + mCount + " result=" + v);
+ }
+ return v;
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
return 1.0f;
}
- return (mAcceleratingAngles) / mAnglesCount;
+ final float v = (mAcceleratingAngles) / mAnglesCount;
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesPercentage: angles=" + mAcceleratingAngles
+ + " count=" + mAnglesCount + " result=" + v);
+ }
+ return v;
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 49b00ce..a70b358 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -229,10 +229,11 @@
// Bump the notification when the bucket dropped.
.setWhen(mWarningTriggerTimeMs)
.setShowWhen(false)
- .setContentTitle(title)
.setContentText(contentText)
+ .setContentTitle(title)
.setOnlyAlertOnce(true)
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
.setVisibility(Notification.VISIBILITY_PUBLIC);
if (hasBatterySettings()) {
nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
@@ -483,16 +484,24 @@
d.setMessage(mContext.getString(R.string.auto_saver_enabled_text,
getLowBatteryAutoTriggerDefaultLevel()));
- // Negative == "got it". Just close the dialog. Battery saver has already been enabled.
- d.setNegativeButton(R.string.auto_saver_okay_action, null);
- d.setPositiveButton(R.string.open_saver_setting_action, (dialog, which) ->
- mContext.startActivity(actionBatterySaverSetting));
+ // "Got it". Just close the dialog. Automatic battery has been enabled already.
+ d.setPositiveButton(R.string.auto_saver_okay_action,
+ (dialog, which) -> onAutoSaverEnabledConfirmationClosed());
+
+ // "Settings" -> Opens the battery saver settings activity.
+ d.setNeutralButton(R.string.open_saver_setting_action, (dialog, which) -> {
+ mContext.startActivity(actionBatterySaverSetting);
+ onAutoSaverEnabledConfirmationClosed();
+ });
d.setShowForAllUsers(true);
- d.setOnDismissListener((dialog) -> mSaverEnabledConfirmation = null);
+ d.setOnDismissListener((dialog) -> onAutoSaverEnabledConfirmationClosed());
d.show();
mSaverEnabledConfirmation = d;
}
+ private void onAutoSaverEnabledConfirmationClosed() {
+ mSaverEnabledConfirmation = null;
+ }
private void setSaverMode(boolean mode, boolean needFirstTimeWarning) {
BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java
index 2ec78cf..019c680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java
@@ -62,7 +62,7 @@
public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
mFsc.onAppOpChanged(code, uid, packageName, active);
mPresenter.getHandler().post(() -> {
- mEntryManager.updateNotificationsForAppOps(code, uid, packageName, active);
+ mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 4b6ab64..ab46b39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -383,8 +383,6 @@
}
mGroupManager.onEntryAdded(entry);
- updateAppOps(entry);
-
updateRankingAndSort(mRankingMap);
}
@@ -403,25 +401,14 @@
updateRankingAndSort(ranking);
}
- private void updateAppOps(Entry entry) {
- final int uid = entry.notification.getUid();
- final String pkg = entry.notification.getPackageName();
- ArraySet<Integer> activeOps = mFsc.getAppOps(entry.notification.getUserId(), pkg);
- if (activeOps != null) {
- int N = activeOps.size();
- for (int i = 0; i < N; i++) {
- updateAppOp(activeOps.valueAt(i), uid, pkg, true);
- }
- }
- }
-
- public void updateAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+ public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
synchronized (mEntries) {
final int N = mEntries.size();
for (int i = 0; i < N; i++) {
Entry entry = mEntries.valueAt(i);
if (uid == entry.notification.getUid()
- && pkg.equals(entry.notification.getPackageName())) {
+ && pkg.equals(entry.notification.getPackageName())
+ && key.equals(entry.key)) {
if (showIcon) {
entry.mActiveAppOps.add(appOp);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 45df450..849cfdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -43,6 +43,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
@@ -665,6 +666,7 @@
}
// Add the expanded view and icon.
mNotificationData.add(entry);
+ tagForeground(entry.notification);
updateNotifications();
}
@@ -726,6 +728,19 @@
mPendingNotifications.put(key, shadeEntry);
}
+ @VisibleForTesting
+ protected void tagForeground(StatusBarNotification notification) {
+ ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
+ notification.getUserId(), notification.getPackageName());
+ if (activeOps != null) {
+ int N = activeOps.size();
+ for (int i = 0; i < N; i++) {
+ updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
+ notification.getPackageName(), true);
+ }
+ }
+ }
+
@Override
public void addNotification(StatusBarNotification notification,
NotificationListenerService.RankingMap ranking) {
@@ -736,10 +751,11 @@
}
}
- public void updateNotificationsForAppOps(int appOp, int uid, String pkg, boolean showIcon) {
- if (mForegroundServiceController.getStandardLayoutKey(
- UserHandle.getUserId(uid), pkg) != null) {
- mNotificationData.updateAppOp(appOp, uid, pkg, showIcon);
+ public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+ String foregroundKey = mForegroundServiceController.getStandardLayoutKey(
+ UserHandle.getUserId(uid), pkg);
+ if (foregroundKey != null) {
+ mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
updateNotifications();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index af77804..d3790d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -51,6 +51,10 @@
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_DRAG_SLOP_PX;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_TOUCH_SLOP_PX;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_DRAG_SLOP_PX;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_TOUCH_SLOP_PX;
/**
* Class to detect gestures on the navigation bar and implement quick scrub.
@@ -69,6 +73,7 @@
private float mTranslation;
private int mTouchDownX;
private int mTouchDownY;
+ private boolean mDragScrubActive;
private boolean mDragPositive;
private boolean mIsVertical;
private boolean mIsRTL;
@@ -82,7 +87,6 @@
private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
private final Rect mTrackRect = new Rect();
private final Paint mTrackPaint = new Paint();
- private final int mScrollTouchSlop;
private final OverviewProxyService mOverviewEventSender;
private final int mTrackThickness;
private final int mTrackPadding;
@@ -115,6 +119,7 @@
@Override
public void onAnimationEnd(Animator animation) {
mQuickScrubActive = false;
+ mDragScrubActive = false;
mTranslation = 0;
mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration());
mHomeButtonView = null;
@@ -123,7 +128,6 @@
public QuickStepController(Context context) {
mContext = context;
- mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mOverviewEventSender = Dependency.get(OverviewProxyService.class);
mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
@@ -177,8 +181,8 @@
final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME;
- int action = event.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
+ int action = event.getActionMasked();
+ switch (action) {
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
@@ -206,21 +210,22 @@
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
- boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff;
- boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff;
- boolean exceededTouchSlop, exceededPerpendicularTouchSlop;
+
+ boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop, exceededScrubDragSlop;
int pos, touchDown, offset, trackSize;
if (mIsVertical) {
- exceededTouchSlop = exceededTouchSlopY;
- exceededPerpendicularTouchSlop = exceededTouchSlopX;
+ exceededScrubTouchSlop = yDiff > QUICK_STEP_TOUCH_SLOP_PX && yDiff > xDiff;
+ exceededSwipeUpTouchSlop = xDiff > QUICK_STEP_DRAG_SLOP_PX && xDiff > yDiff;
+ exceededScrubDragSlop = yDiff > QUICK_SCRUB_DRAG_SLOP_PX && yDiff > xDiff;
pos = y;
touchDown = mTouchDownY;
offset = pos - mTrackRect.top;
trackSize = mTrackRect.height();
} else {
- exceededTouchSlop = exceededTouchSlopX;
- exceededPerpendicularTouchSlop = exceededTouchSlopY;
+ exceededScrubTouchSlop = xDiff > QUICK_STEP_TOUCH_SLOP_PX && xDiff > yDiff;
+ exceededSwipeUpTouchSlop = yDiff > QUICK_SCRUB_TOUCH_SLOP_PX && yDiff > xDiff;
+ exceededScrubDragSlop = xDiff > QUICK_SCRUB_DRAG_SLOP_PX && xDiff > yDiff;
pos = x;
touchDown = mTouchDownX;
offset = pos - mTrackRect.left;
@@ -228,7 +233,7 @@
}
// Decide to start quickstep if dragging away from the navigation bar, otherwise in
// the parallel direction, decide to start quickscrub. Only one may run.
- if (!mQuickScrubActive && exceededPerpendicularTouchSlop) {
+ if (!mQuickScrubActive && exceededSwipeUpTouchSlop) {
if (mNavigationBarView.isQuickStepSwipeUpEnabled()) {
startQuickStep(event);
}
@@ -244,29 +249,38 @@
offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
}
- // Control the button movement
- if (!mQuickScrubActive && exceededTouchSlop) {
- boolean allowDrag = !mDragPositive
- ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
- if (allowDrag) {
+ final boolean allowDrag = !mDragPositive
+ ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
+ if (allowDrag) {
+ // Passing the drag slop is for visual feedback and will not initiate anything
+ if (!mDragScrubActive && exceededScrubDragSlop) {
mDownOffset = offset;
+ mDragScrubActive = true;
+ }
+
+ // Passing the drag slop then touch slop will start quick step
+ if (!mQuickScrubActive && exceededScrubTouchSlop) {
homeButton.abortCurrentGesture();
startQuickScrub();
}
}
- if (mQuickScrubActive && (mDragPositive && offset >= 0
+
+ if ((mQuickScrubActive || mDragScrubActive) && (mDragPositive && offset >= 0
|| !mDragPositive && offset <= 0)) {
- float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
mTranslation = !mDragPositive
- ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
- : Utilities.clamp(offset - mDownOffset, 0, trackSize);
- try {
- mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
+ ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
+ : Utilities.clamp(offset - mDownOffset, 0, trackSize);
+ if (mQuickScrubActive) {
+ float scrubFraction =
+ Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
+ try {
+ mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send progress of quick scrub.", e);
}
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send progress of quick scrub.", e);
}
if (mIsVertical) {
mHomeButtonView.setTranslationY(mTranslation);
@@ -283,7 +297,9 @@
}
// Proxy motion events to launcher if not handled by quick scrub
- if (!mQuickScrubActive && mAllowGestureDetection) {
+ // Proxy motion events up/cancel that would be sent after long press on any nav button
+ if (!mQuickScrubActive && (mAllowGestureDetection || action == MotionEvent.ACTION_CANCEL
+ || action == MotionEvent.ACTION_UP)) {
proxyMotionEvents(event);
}
return mQuickScrubActive || mQuickStepStarted;
@@ -370,10 +386,14 @@
mOverviewEventSender.notifyQuickStepStarted();
mNavigationBarView.getHomeButton().abortCurrentGesture();
mHandler.removeCallbacksAndMessages(null);
+
+ if (mDragScrubActive) {
+ animateEnd();
+ }
}
private void startQuickScrub() {
- if (!mQuickScrubActive) {
+ if (!mQuickScrubActive && mDragScrubActive) {
mQuickScrubActive = true;
mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
@@ -391,15 +411,17 @@
}
private void endQuickScrub(boolean animate) {
- if (mQuickScrubActive) {
+ if (mQuickScrubActive || mDragScrubActive) {
animateEnd();
- try {
- mOverviewEventSender.getProxy().onQuickScrubEnd();
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub End");
+ if (mQuickScrubActive) {
+ try {
+ mOverviewEventSender.getProxy().onQuickScrubEnd();
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub End");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send end of quick scrub.", e);
}
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send end of quick scrub.", e);
}
}
if (mHomeButtonView != null && !animate) {
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 2c025b5..28f3162 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -807,7 +807,7 @@
@VisibleForTesting
protected WakeLock createWakeLock() {
return new DelayedWakeLock(getHandler(),
- WakeLock.createPartial(mContext, "Doze"));
+ WakeLock.createPartial(mContext, "Scrims"));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 378dad7..6a8d3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -69,6 +69,10 @@
setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
}
+ public void setNeutralButton(int resId, OnClickListener onClick) {
+ setButton(BUTTON_NEUTRAL, mContext.getString(resId), onClick);
+ }
+
public static void setShowForAllUsers(Dialog dialog, boolean show) {
if (show) {
dialog.getWindow().getAttributes().privateFlags |=
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 44c2757..2fed3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,8 +52,11 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.VibratorHelper;
+import static android.view.KeyEvent.KEYCODE_HOME;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_SCRUB_TOUCH_SLOP_PX;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_TOUCH_SLOP_PX;
public class KeyButtonView extends ImageView implements ButtonInterface {
private static final String TAG = KeyButtonView.class.getSimpleName();
@@ -62,9 +65,9 @@
private int mContentDescriptionRes;
private long mDownTime;
private int mCode;
- private int mTouchSlop;
private int mTouchDownX;
private int mTouchDownY;
+ private boolean mIsVertical;
private boolean mSupportsLongpress = true;
private AudioManager mAudioManager;
private boolean mGestureAborted;
@@ -115,7 +118,6 @@
a.recycle();
setClickable(true);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRipple = new KeyButtonRipple(context, this);
@@ -235,8 +237,11 @@
case MotionEvent.ACTION_MOVE:
x = (int)ev.getRawX();
y = (int)ev.getRawY();
- boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop;
- boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop;
+
+ boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) >
+ (mIsVertical ? QUICK_SCRUB_TOUCH_SLOP_PX : QUICK_STEP_TOUCH_SLOP_PX);
+ boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) >
+ (mIsVertical ? QUICK_STEP_TOUCH_SLOP_PX : QUICK_SCRUB_TOUCH_SLOP_PX);
if (exceededTouchSlopX || exceededTouchSlopY) {
// When quick step is enabled, prevent animating the ripple triggered by
// setPressed and decide to run it on touch up
@@ -270,8 +275,12 @@
if (mCode != 0) {
if (doIt) {
// If there was a pending remote recents animation, then we need to
- // cancel the animation now before we handle the button itself
- ActivityManagerWrapper.getInstance().cancelRecentsAnimation();
+ // cancel the animation now before we handle the button itself. In the case
+ // where we are going home and the recents animation has already started,
+ // just cancel the recents animation, leaving the home stack in place
+ boolean isHomeKey = mCode == KEYCODE_HOME;
+ ActivityManagerWrapper.getInstance().cancelRecentsAnimation(!isHomeKey);
+
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
} else {
@@ -342,7 +351,7 @@
@Override
public void setVertical(boolean vertical) {
- //no op
+ mIsVertical = vertical;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index 5ec3dff..e1814098 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,7 +23,7 @@
*/
public class DelayedWakeLock implements WakeLock {
- private static final long RELEASE_DELAY_MS = 120;
+ private static final long RELEASE_DELAY_MS = 240;
private final Handler mHandler;
private final WakeLock mInner;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java
index 2a48c4b..dc0e2b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java
@@ -86,7 +86,7 @@
mListener.onOpActiveChanged(
AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
waitForIdleSync(mHandler);
- verify(mEntryManager, times(1)).updateNotificationsForAppOps(
+ verify(mEntryManager, times(1)).updateNotificationsForAppOp(
AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
index 5e27fde..5ec77ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
@@ -139,32 +139,7 @@
Assert.assertTrue(mRow.getEntry().channel != null);
}
- @Test
- public void testAdd_appOpsAdded() {
- ArraySet<Integer> expected = new ArraySet<>();
- expected.add(3);
- expected.add(235);
- expected.add(1);
- when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(),
- mRow.getEntry().notification.getPackageName())).thenReturn(expected);
- mNotificationData.add(mRow.getEntry());
- assertEquals(expected.size(),
- mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size());
- for (int op : expected) {
- assertTrue(" entry missing op " + op,
- mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
- }
- }
-
- @Test
- public void testAdd_noExistingAppOps() {
- when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(),
- mRow.getEntry().notification.getPackageName())).thenReturn(null);
-
- mNotificationData.add(mRow.getEntry());
- assertEquals(0, mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size());
- }
@Test
public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
@@ -181,7 +156,9 @@
for (int op : expectedOps) {
mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
- NotificationTestHelper.PKG, true);
+ NotificationTestHelper.PKG, mRow.getEntry().key, true);
+ mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+ NotificationTestHelper.PKG, row2.getEntry().key, true);
}
for (int op : expectedOps) {
assertTrue(mRow.getEntry().key + " doesn't have op " + op,
@@ -205,12 +182,12 @@
for (int op : expectedOps) {
mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
- NotificationTestHelper.PKG, true);
+ NotificationTestHelper.PKG, row2.getEntry().key, true);
}
expectedOps.remove(OP_ACCEPT_HANDOVER);
mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
- NotificationTestHelper.PKG, false);
+ NotificationTestHelper.PKG, row2.getEntry().key, false);
assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index 3703d6a..7cfd7a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -37,18 +37,15 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArraySet;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
@@ -56,12 +53,13 @@
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -285,13 +283,12 @@
com.android.systemui.util.Assert.isNotMainThread();
when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
- .thenReturn("something");
+ .thenReturn(mEntry.key);
mEntry.row = mRow;
mEntryManager.getNotificationData().add(mEntry);
-
mHandler.post(() -> {
- mEntryManager.updateNotificationsForAppOps(
+ mEntryManager.updateNotificationsForAppOp(
AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
mEntry.notification.getPackageName(), true);
});
@@ -309,10 +306,65 @@
when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
.thenReturn(null);
mHandler.post(() -> {
- mEntryManager.updateNotificationsForAppOps(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+ mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
});
waitForIdleSync(mHandler);
verify(mPresenter, never()).updateNotificationViews();
}
+
+ @Test
+ public void testAddNotificationExistingAppOps() {
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+ ArraySet<Integer> expected = new ArraySet<>();
+ expected.add(3);
+ expected.add(235);
+ expected.add(1);
+
+ when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn(expected);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn(mEntry.key);
+
+ mEntryManager.tagForeground(mEntry.notification);
+
+ Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size());
+ for (int op : expected) {
+ assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op));
+ }
+ }
+
+ @Test
+ public void testAdd_noExistingAppOps() {
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn(mEntry.key);
+ when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn(null);
+
+ mEntryManager.tagForeground(mEntry.notification);
+ Assert.assertEquals(0, mEntry.mActiveAppOps.size());
+ }
+
+ @Test
+ public void testAdd_existingAppOpsNotForegroundNoti() {
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(3);
+ ops.add(235);
+ ops.add(1);
+ when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn(ops);
+ when(mForegroundServiceController.getStandardLayoutKey(
+ mEntry.notification.getUserId(),
+ mEntry.notification.getPackageName())).thenReturn("something else");
+
+ mEntryManager.tagForeground(mEntry.notification);
+ Assert.assertEquals(0, mEntry.mActiveAppOps.size());
+ }
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 26b83f5..fb5fba0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1344,13 +1344,7 @@
* @param provider the name of the location provider
*/
private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
- if (mEnabledProviders.contains(provider)) {
- return true;
- }
- if (mDisabledProviders.contains(provider)) {
- return false;
- }
- return isLocationProviderEnabledForUser(provider, mCurrentUserId);
+ return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
}
/**
@@ -1359,13 +1353,33 @@
* processes belonging to background users.
*
* @param provider the name of the location provider
- * @param uid the requestor's UID
+ * @param userId the user id to query
*/
- private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
+ private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
+ if (mEnabledProviders.contains(provider)) {
+ return true;
+ }
+ if (mDisabledProviders.contains(provider)) {
+ return false;
+ }
+ return isLocationProviderEnabledForUser(provider, userId);
+ }
+
+
+ /**
+ * Returns "true" if access to the specified location provider is allowed by the specified
+ * user's settings. Access to all location providers is forbidden to non-location-provider
+ * processes belonging to background users.
+ *
+ * @param provider the name of the location provider
+ * @param uid the requestor's UID
+ * @param userId the user id to query
+ */
+ private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
- return isAllowedByCurrentUserSettingsLocked(provider);
+ return isAllowedByUserSettingsLockedForUser(provider, userId);
}
/**
@@ -1572,7 +1586,8 @@
continue;
}
if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
- if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
+ if (enabledOnly
+ && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
continue;
}
if (criteria != null && !LocationProvider.propertiesMeetCriteria(
@@ -2098,7 +2113,7 @@
oldRecord.disposeLocked(false);
}
- boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
+ boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
if (isProviderEnabled) {
applyRequirementsLocked(name);
} else {
@@ -2219,7 +2234,7 @@
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) return null;
- if (!isAllowedByUserSettingsLocked(name, uid)) return null;
+ if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Location location;
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
@@ -2540,6 +2555,173 @@
}
/**
+ * Returns the current location enabled/disabled status for a user
+ *
+ * @param userId the id of the user
+ * @return true if location is enabled
+ */
+ @Override
+ public boolean isLocationEnabledForUser(int userId) {
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final String allowedProviders = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ userId);
+ if (allowedProviders == null) {
+ return false;
+ }
+ final List<String> providerList = Arrays.asList(allowedProviders.split(","));
+ for(String provider : mRealProviders.keySet()) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ if (providerList.contains(provider)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Enable or disable location for a user
+ *
+ * @param enabled true to enable location, false to disable location
+ * @param userId the id of the user
+ */
+ @Override
+ public void setLocationEnabledForUser(boolean enabled, int userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "Requires WRITE_SECURE_SETTINGS permission");
+
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final Set<String> allRealProviders = mRealProviders.keySet();
+ // Update all providers on device plus gps and network provider when disabling
+ // location
+ Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
+ allProvidersSet.addAll(allRealProviders);
+ // When disabling location, disable gps and network provider that could have been
+ // enabled by location mode api.
+ if (enabled == false) {
+ allProvidersSet.add(LocationManager.GPS_PROVIDER);
+ allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
+ }
+ if (allProvidersSet.isEmpty()) {
+ return;
+ }
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ final String prefix = enabled ? "+" : "-";
+ StringBuilder locationProvidersAllowed = new StringBuilder();
+ for (String provider : allProvidersSet) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ locationProvidersAllowed.append(prefix);
+ locationProvidersAllowed.append(provider);
+ locationProvidersAllowed.append(",");
+ }
+ // Remove the trailing comma
+ locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ locationProvidersAllowed.toString(),
+ userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Returns the current enabled/disabled status of a location provider and user
+ *
+ * @param provider name of the provider
+ * @param userId the id of the user
+ * @return true if the provider exists and is enabled
+ */
+ @Override
+ public boolean isProviderEnabledForUser(String provider, int userId) {
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // so we discourage its use
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+
+ int uid = Binder.getCallingUid();
+ synchronized (mLock) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ return p != null
+ && isAllowedByUserSettingsLocked(provider, uid, userId);
+ }
+ }
+
+ /**
+ * Enable or disable a single location provider.
+ *
+ * @param provider name of the provider
+ * @param enabled true to enable the provider. False to disable the provider
+ * @param userId the id of the user to set
+ * @return true if the value was set, false on errors
+ */
+ @Override
+ public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "Requires WRITE_SECURE_SETTINGS permission");
+
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // so we discourage its use
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ // No such provider exists
+ if (!mProvidersByName.containsKey(provider)) return false;
+
+ // If it is a test provider, do not write to Settings.Secure
+ if (mMockProviders.containsKey(provider)) {
+ setTestProviderEnabled(provider, enabled);
+ return true;
+ }
+
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ String providerChange = (enabled ? "+" : "-") + provider;
+ return Settings.Secure.putStringForUser(
+ mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ providerChange, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Read location provider status from Settings.Secure
*
* @param provider the location provider to query
@@ -2560,6 +2742,23 @@
}
/**
+ * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
+ * current user id
+ *
+ * @param userId the user id to get or set value
+ */
+ private void checkInteractAcrossUsersPermission(int userId) {
+ int uid = Binder.getCallingUid();
+ if (UserHandle.getUserId(uid) != userId) {
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+ }
+ }
+ }
+
+ /**
* Returns "true" if the UID belongs to a bound location provider.
*
* @param uid the uid
@@ -3076,7 +3275,11 @@
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
+ setTestProviderEnabled(provider, enabled);
+ }
+ /** Enable or disable a test location provider. */
+ private void setTestProviderEnabled(String provider, boolean enabled) {
synchronized (mLock) {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f97c6d6..db52b97 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -204,6 +204,8 @@
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_HOME_IN_PLACE;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -257,7 +259,6 @@
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.admin.DevicePolicyCache;
-import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
@@ -5238,12 +5239,14 @@
}
@Override
- public void cancelRecentsAnimation() {
+ public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
- mWindowManager.cancelRecentsAnimation();
+ mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition
+ ? REORDER_MOVE_HOME_TO_ORIGINAL_POSITION
+ : REORDER_KEEP_HOME_IN_PLACE);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 9df321c..99337b8 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -23,6 +23,8 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_TOP;
import android.app.ActivityOptions;
import android.content.ComponentName;
@@ -32,6 +34,7 @@
import android.os.Trace;
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
+import com.android.server.wm.RecentsAnimationController;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
import com.android.server.wm.WindowManagerService;
@@ -123,7 +126,7 @@
// Fetch all the surface controls and pass them to the client to get the animation
// started
- mWindowManager.cancelRecentsAnimation();
+ mWindowManager.cancelRecentsAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds());
@@ -140,7 +143,7 @@
}
@Override
- public void onAnimationFinished(boolean moveHomeToTop) {
+ public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode) {
synchronized (mService) {
if (mWindowManager.getRecentsAnimationController() == null) return;
@@ -151,9 +154,8 @@
"RecentsAnimation#onAnimationFinished_inSurfaceTransaction");
mWindowManager.deferSurfaceLayout();
try {
- mWindowManager.cleanupRecentsAnimation(moveHomeToTop);
+ mWindowManager.cleanupRecentsAnimation(reorderMode);
- // Move the home stack to the front
final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
if (homeActivity == null) {
return;
@@ -162,15 +164,19 @@
// Restore the launched-behind state
homeActivity.mLaunchTaskBehind = false;
- if (moveHomeToTop) {
+ if (reorderMode == REORDER_MOVE_HOME_TO_TOP) {
// Bring the home stack to the front
final ActivityStack homeStack = homeActivity.getStack();
mStackSupervisor.mNoAnimActivities.add(homeActivity);
homeStack.moveToFront("RecentsAnimation.onAnimationFinished()");
- } else {
+ } else if (reorderMode == REORDER_MOVE_HOME_TO_ORIGINAL_POSITION){
// Restore the home stack to its previous position
final ActivityDisplay display = homeActivity.getDisplay();
display.moveHomeStackBehindStack(mRestoreHomeBehindStack);
+ } else {
+ // Keep home stack in place, nothing changes, so ignore the transition logic
+ // below
+ return;
}
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
@@ -180,6 +186,11 @@
// No reason to wait for the pausing activity in this case, as the hiding of
// surfaces needs to be done immediately.
mWindowManager.executeAppTransition();
+
+ // After reordering the stacks, reset the minimized state. At this point, either
+ // home is now top-most and we will stay minimized (if in split-screen), or we
+ // will have returned to the app, and the minimized state should be reset
+ mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c8b6b50..3e82c25 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -320,13 +320,13 @@
0, // STREAM_SYSTEM
0, // STREAM_RING
0, // STREAM_MUSIC
- 0, // STREAM_ALARM
+ 1, // STREAM_ALARM
0, // STREAM_NOTIFICATION
0, // STREAM_BLUETOOTH_SCO
0, // STREAM_SYSTEM_ENFORCED
0, // STREAM_DTMF
0, // STREAM_TTS
- 0 // STREAM_ACCESSIBILITY
+ 1 // STREAM_ACCESSIBILITY
};
/* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
@@ -1208,6 +1208,8 @@
System.VOLUME_SETTINGS_INT[a11yStreamAlias];
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
mStreamStates[a11yStreamAlias], caller);
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].refreshRange(
+ mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY]);
}
}
if (sIndependentA11yVolume) {
@@ -1389,7 +1391,15 @@
}
private int rescaleIndex(int index, int srcStream, int dstStream) {
- return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
+ final int rescaled =
+ (index * mStreamStates[dstStream].getMaxIndex()
+ + mStreamStates[srcStream].getMaxIndex() / 2)
+ / mStreamStates[srcStream].getMaxIndex();
+ if (rescaled < mStreamStates[dstStream].getMinIndex()) {
+ return mStreamStates[dstStream].getMinIndex();
+ } else {
+ return rescaled;
+ }
}
///////////////////////////////////////////////////////////////////////////
@@ -4602,8 +4612,8 @@
// 4 VolumeStreamState.class
public class VolumeStreamState {
private final int mStreamType;
- private final int mIndexMin;
- private final int mIndexMax;
+ private int mIndexMin;
+ private int mIndexMax;
private boolean mIsMuted;
private String mVolumeIndexSettingName;
@@ -4889,6 +4899,24 @@
}
/**
+ * Updates the min/max index values from another stream. Use this when changing the alias
+ * for the current stream type.
+ * @param sourceStreamType
+ */
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
+ public void refreshRange(int sourceStreamType) {
+ mIndexMin = MIN_STREAM_VOLUME[sourceStreamType] * 10;
+ mIndexMax = MAX_STREAM_VOLUME[sourceStreamType] * 10;
+ // verify all current volumes are within bounds
+ for (int i = 0 ; i < mIndexMap.size(); i++) {
+ final int device = mIndexMap.keyAt(i);
+ final int index = mIndexMap.valueAt(i);
+ mIndexMap.put(device, getValidIndex(index));
+ }
+ }
+
+ /**
* Copies all device/index pairs from the given VolumeStreamState after initializing
* them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState
* has the same stream type as this instance.
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 88df195..905c7e3 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -686,10 +686,15 @@
}
public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) {
- ArrayList<AmbientBrightnessDayStats> stats = mAmbientBrightnessStatsTracker.getUserStats(
- userId);
- return (stats != null) ? new ParceledListSlice<>(stats) : new ParceledListSlice<>(
- Collections.EMPTY_LIST);
+ if (mAmbientBrightnessStatsTracker != null) {
+ ArrayList<AmbientBrightnessDayStats> stats =
+ mAmbientBrightnessStatsTracker.getUserStats(
+ userId);
+ if (stats != null) {
+ return new ParceledListSlice<>(stats);
+ }
+ }
+ return ParceledListSlice.emptyList();
}
// Not allowed to keep the SensorEvent so used to copy the data we care about.
diff --git a/services/core/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
index 3d6f7ad..720eaaa5 100644
--- a/services/core/java/com/android/server/input/InputWindowHandle.java
+++ b/services/core/java/com/android/server/input/InputWindowHandle.java
@@ -92,7 +92,7 @@
public int inputFeatures;
// Display this input is on.
- public final int displayId;
+ public int displayId;
private native void nativeDispose();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e55c715..7813e70 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2289,6 +2289,12 @@
}
@Override
+ public int getBlockedChannelCount(String pkg, int uid) {
+ enforceSystemOrSystemUI("getBlockedChannelCount");
+ return mRankingHelper.getBlockedChannelCount(pkg, uid);
+ }
+
+ @Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
checkCallerIsSystem();
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 98d5c9a..43d393a 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -619,7 +621,7 @@
updateConfig();
return;
}
- if (channel.getImportance() < NotificationManager.IMPORTANCE_NONE
+ if (channel.getImportance() < IMPORTANCE_NONE
|| channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
throw new IllegalArgumentException("Invalid importance level");
}
@@ -959,6 +961,23 @@
return deletedCount;
}
+ public int getBlockedChannelCount(String pkg, int uid) {
+ Preconditions.checkNotNull(pkg);
+ int blockedCount = 0;
+ Record r = getRecord(pkg, uid);
+ if (r == null) {
+ return blockedCount;
+ }
+ int N = r.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = r.channels.valueAt(i);
+ if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) {
+ blockedCount++;
+ }
+ }
+ return blockedCount;
+ }
+
/**
* Sets importance.
*/
@@ -969,12 +988,12 @@
}
public void setEnabled(String packageName, int uid, boolean enabled) {
- boolean wasEnabled = getImportance(packageName, uid) != NotificationManager.IMPORTANCE_NONE;
+ boolean wasEnabled = getImportance(packageName, uid) != IMPORTANCE_NONE;
if (wasEnabled == enabled) {
return;
}
setImportance(packageName, uid,
- enabled ? DEFAULT_IMPORTANCE : NotificationManager.IMPORTANCE_NONE);
+ enabled ? DEFAULT_IMPORTANCE : IMPORTANCE_NONE);
}
@VisibleForTesting
@@ -1199,7 +1218,7 @@
ArrayMap<Integer, String> packageBans = new ArrayMap<>(N);
for (int i = 0; i < N; i++) {
final Record r = mRecords.valueAt(i);
- if (r.importance == NotificationManager.IMPORTANCE_NONE) {
+ if (r.importance == IMPORTANCE_NONE) {
packageBans.put(r.uid, r.pkg);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2e530af..0e0bfbd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17,12 +17,12 @@
package com.android.server.pm;
import static android.Manifest.permission.DELETE_PACKAGES;
-import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
-import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
+import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
@@ -167,8 +167,8 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageList;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
@@ -310,10 +310,10 @@
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.PermissionManagerService;
-import com.android.server.pm.permission.PermissionManagerInternal;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerInternal;
import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionsState;
import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.security.VerityUtils;
@@ -8185,35 +8185,22 @@
private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId, name);
- final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
- // reader
+ final int callingUid = Binder.getCallingUid();
synchronized (mPackages) {
final PackageParser.Provider provider = mProvidersByAuthority.get(name);
PackageSetting ps = provider != null
? mSettings.mPackages.get(provider.owner.packageName)
: null;
if (ps != null) {
- final boolean isInstantApp = ps.getInstantApp(userId);
- // normal application; filter out instant application provider
- if (instantAppPkgName == null && isInstantApp) {
- return null;
- }
- // instant application; filter out other instant applications
- if (instantAppPkgName != null
- && isInstantApp
- && !provider.owner.packageName.equals(instantAppPkgName)) {
- return null;
- }
- // instant application; filter out non-exposed provider
- if (instantAppPkgName != null
- && !isInstantApp
- && (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0) {
- return null;
- }
// provider not enabled
if (!mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)) {
return null;
}
+ final ComponentName component =
+ new ComponentName(provider.info.packageName, provider.info.name);
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ return null;
+ }
return PackageParser.generateProviderInfo(
provider, flags, ps.readUserState(userId), userId);
}
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index ba67ff6..112d93c 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -161,7 +161,10 @@
// Timeout callback to ensure we continue the animation if waiting for resuming or app
// windows drawn fails
- private final Runnable mResumeRunnable = () -> resume();
+ private final Runnable mResumeRunnable = () -> {
+ if (DEBUG) Slog.d(TAG, "pause: timed out waiting for windows drawn");
+ resume();
+ };
BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
@SchedulePipModeChangedState int schedulePipModeChangedState,
@@ -213,7 +216,7 @@
// When starting an animation from fullscreen, pause here and wait for the
// windows-drawn signal before we start the rest of the transition down into PiP.
- if (mMoveFromFullscreen) {
+ if (mMoveFromFullscreen && mTarget.shouldDeferStartOnMoveToFullscreen()) {
pause();
}
} else if (mPrevSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END &&
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 647a2d6..68be4e8 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -34,6 +34,12 @@
void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
/**
+ * @return Whether the animation should be paused waiting for the windows to draw before
+ * entering PiP.
+ */
+ boolean shouldDeferStartOnMoveToFullscreen();
+
+ /**
* Sets the size of the target (without any intermediate steps, like scheduling animation)
* but freezes the bounds of any tasks in the target at taskBounds, to allow for more
* flexibility during resizing. Only works for the pinned stack at the moment. This will
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c4f2bd4..0771b53 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3568,7 +3568,8 @@
if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
t.setLayer(mSplitScreenDividerAnchor, layer++);
}
- if (s.isAppAnimating() && state != ALWAYS_ON_TOP_STATE) {
+ if ((s.isTaskAnimating() || s.isAppAnimating())
+ && state != ALWAYS_ON_TOP_STATE) {
// Ensure the animation layer ends up above the
// highest animating stack and no higher.
layerForAnimationLayer = layer++;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 5e2bb10..2cd2ef1 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -666,13 +666,16 @@
}
final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
+ final boolean minimizedForRecentsAnimation = recentsAnim != null &&
+ recentsAnim.isSplitScreenMinimized();
boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
if (homeVisible && topSecondaryStack != null) {
// Home should only be considered visible if it is greater or equal to the top secondary
// stack in terms of z-order.
homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
}
- setMinimizedDockedStack(homeVisible, animate);
+ setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate);
}
private boolean isWithinDisplay(Task task) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 7274aee..c4f5197 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,6 +29,7 @@
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import android.annotation.IntDef;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
import android.graphics.Point;
@@ -67,12 +68,25 @@
private static final boolean DEBUG = false;
private static final long FAILSAFE_DELAY = 1000;
+ public static final int REORDER_KEEP_HOME_IN_PLACE = 0;
+ public static final int REORDER_MOVE_HOME_TO_TOP = 1;
+ public static final int REORDER_MOVE_HOME_TO_ORIGINAL_POSITION = 2;
+
+ @IntDef(prefix = { "REORDER_MODE_" }, value = {
+ REORDER_KEEP_HOME_IN_PLACE,
+ REORDER_MOVE_HOME_TO_TOP,
+ REORDER_MOVE_HOME_TO_ORIGINAL_POSITION
+ })
+ public @interface ReorderMode {}
+
private final WindowManagerService mService;
private final IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
private final int mDisplayId;
- private final Runnable mFailsafeRunnable = this::cancelAnimation;
+ private final Runnable mFailsafeRunnable = () -> {
+ cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
+ };
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mHomeAppToken;
@@ -84,16 +98,20 @@
private boolean mPendingStart = true;
// Set when the animation has been canceled
- private boolean mCanceled = false;
+ private boolean mCanceled;
// Whether or not the input consumer is enabled. The input consumer must be both registered and
// enabled for it to start intercepting touch events.
private boolean mInputConsumerEnabled;
+ // Whether or not the recents animation should cause the primary split-screen stack to be
+ // minimized
+ private boolean mSplitScreenMinimized;
+
private Rect mTmpRect = new Rect();
public interface RecentsAnimationCallbacks {
- void onAnimationFinished(boolean moveHomeToTop);
+ void onAnimationFinished(@ReorderMode int reorderMode);
}
private final IRecentsAnimationController mController =
@@ -102,7 +120,7 @@
@Override
public TaskSnapshot screenshotTask(int taskId) {
if (DEBUG) Log.d(TAG, "screenshotTask(" + taskId + "): mCanceled=" + mCanceled);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
if (mCanceled) {
@@ -131,7 +149,7 @@
@Override
public void finish(boolean moveHomeToTop) {
if (DEBUG) Log.d(TAG, "finish(" + moveHomeToTop + "): mCanceled=" + mCanceled);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
if (mCanceled) {
@@ -141,7 +159,9 @@
// Note, the callback will handle its own synchronization, do not lock on WM lock
// prior to calling the callback
- mCallbacks.onAnimationFinished(moveHomeToTop);
+ mCallbacks.onAnimationFinished(moveHomeToTop
+ ? REORDER_MOVE_HOME_TO_TOP
+ : REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -150,7 +170,7 @@
@Override
public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
throws RemoteException {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
@@ -167,7 +187,7 @@
public void setInputConsumerEnabled(boolean enabled) {
if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled="
+ mCanceled);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
if (mCanceled) {
@@ -182,6 +202,23 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public void setSplitScreenMinimized(boolean minimized) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService.getWindowManagerLock()) {
+ if (mCanceled) {
+ return;
+ }
+
+ mSplitScreenMinimized = minimized;
+ mService.checkSplitScreenMinimizedChanged(true /* animate */);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
/**
@@ -222,14 +259,14 @@
// Skip the animation if there is nothing to animate
if (mPendingAnimations.isEmpty()) {
- cancelAnimation();
+ cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
return;
}
try {
mRunner.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
- cancelAnimation();
+ cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
return;
}
@@ -299,7 +336,7 @@
reasons).sendToTarget();
}
- void cancelAnimation() {
+ void cancelAnimation(@ReorderMode int reorderMode) {
if (DEBUG) Log.d(TAG, "cancelAnimation()");
synchronized (mService.getWindowManagerLock()) {
if (mCanceled) {
@@ -314,18 +351,20 @@
Slog.e(TAG, "Failed to cancel recents animation", e);
}
}
+
// Clean up and return to the previous app
// Don't hold the WM lock here as it calls back to AM/RecentsAnimation
- mCallbacks.onAnimationFinished(false /* moveHomeToTop */);
+ mCallbacks.onAnimationFinished(reorderMode);
}
- void cleanupAnimation(boolean moveHomeToTop) {
+ void cleanupAnimation(@ReorderMode int reorderMode) {
if (DEBUG) Log.d(TAG, "cleanupAnimation(): mPendingAnimations="
+ mPendingAnimations.size());
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
adapter.mTask.setCanAffectSystemUiFlags(true);
- if (moveHomeToTop) {
+ if (reorderMode == REORDER_MOVE_HOME_TO_TOP
+ || reorderMode == REORDER_KEEP_HOME_IN_PLACE) {
adapter.mTask.dontAnimateDimExit();
}
adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
@@ -333,7 +372,7 @@
mPendingAnimations.clear();
mRunner.asBinder().unlinkToDeath(this, 0);
-
+ // Clear associated input consumers
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
}
@@ -344,7 +383,7 @@
@Override
public void binderDied() {
- cancelAnimation();
+ cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
}
void checkAnimationReady(WallpaperController wallpaperController) {
@@ -358,6 +397,10 @@
}
}
+ boolean isSplitScreenMinimized() {
+ return mSplitScreenMinimized;
+ }
+
boolean isWallpaperVisible(WindowState w) {
return w != null && w.mAppToken != null && mHomeAppToken == w.mAppToken
&& isHomeAppOverWallpaper();
@@ -389,6 +432,15 @@
return mHomeAppToken.windowsCanBeWallpaperTarget();
}
+ boolean isAnimatingTask(Task task) {
+ for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ if (task == mPendingAnimations.get(i).mTask) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isAnimatingApp(AppWindowToken appToken) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final Task task = mPendingAnimations.get(i).mTask;
@@ -409,18 +461,18 @@
private OnAnimationFinishedCallback mCapturedFinishCallback;
private final boolean mIsRecentTaskInvisible;
private RemoteAnimationTarget mTarget;
+ private final Point mPosition = new Point();
+ private final Rect mBounds = new Rect();
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
mTask = task;
mIsRecentTaskInvisible = isRecentTaskInvisible;
+ final WindowContainer container = mTask.getParent();
+ container.getRelativePosition(mPosition);
+ container.getBounds(mBounds);
}
RemoteAnimationTarget createRemoteAnimationApp() {
- final Point position = new Point();
- final Rect bounds = new Rect();
- final WindowContainer container = mTask.getParent();
- container.getRelativePosition(position);
- container.getBounds(bounds);
final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
if (mainWindow == null) {
return null;
@@ -429,7 +481,7 @@
InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
!mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
- insets, mTask.getPrefixOrderIndex(), position, bounds,
+ insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
return mTarget;
}
@@ -452,13 +504,14 @@
@Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
OnAnimationFinishedCallback finishCallback) {
+ t.setPosition(animationLeash, mPosition.x, mPosition.y);
mCapturedLeash = animationLeash;
mCapturedFinishCallback = finishCallback;
}
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
- cancelAnimation();
+ cancelAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e8d3210..95223d8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -44,6 +44,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
+import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
@@ -559,6 +560,23 @@
&& !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
}
+ @Override
+ public SurfaceControl getAnimationLeashParent() {
+ // Reparent to the animation layer so that we aren't clipped by the non-minimized
+ // stack bounds, currently we only animate the task for the recents animation
+ return getAppAnimationLayer(false /* boosted */);
+ }
+
+ boolean isTaskAnimating() {
+ final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
+ if (recentsAnim != null) {
+ if (recentsAnim.isAnimatingTask(this)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
WindowState getTopVisibleAppMainWindow() {
final AppWindowToken token = getTopVisibleAppToken();
return token != null ? token.findMainWindow() : null;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 62754ad..2175c6b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -33,8 +33,6 @@
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
@@ -47,6 +45,8 @@
import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
import static com.android.server.wm.StackProto.TASKS;
import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.CallSuper;
import android.content.res.Configuration;
@@ -62,12 +62,10 @@
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
-
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
import com.android.server.EventLogTags;
-
import java.io.PrintWriter;
public class TaskStack extends WindowContainer<Task> implements
@@ -1333,6 +1331,20 @@
return mMinimizeAmount != 0f;
}
+ /**
+ * @return {@code true} if we have a {@link Task} that is animating (currently only used for the
+ * recents animation); {@code false} otherwise.
+ */
+ boolean isTaskAnimating() {
+ for (int j = mChildren.size() - 1; j >= 0; j--) {
+ final Task task = mChildren.get(j);
+ if (task.isTaskAnimating()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@CallSuper
@Override
public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
@@ -1687,6 +1699,25 @@
}
}
+ @Override
+ public boolean shouldDeferStartOnMoveToFullscreen() {
+ // Workaround for the recents animation -- normally we need to wait for the new activity to
+ // show before starting the PiP animation, but because we start and show the home activity
+ // early for the recents animation prior to the PiP animation starting, there is no
+ // subsequent all-drawn signal. In this case, we can skip the pause when the home stack is
+ // already visible and drawn.
+ final TaskStack homeStack = mDisplayContent.getHomeStack();
+ if (homeStack == null) {
+ return true;
+ }
+ final Task homeTask = homeStack.getTopChild();
+ final AppWindowToken homeApp = homeTask.getTopVisibleAppToken();
+ if (!homeTask.isVisible() || homeApp == null) {
+ return true;
+ }
+ return !homeApp.allDrawn;
+ }
+
/**
* @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
* bounds and we have a deferred PiP mode changed callback set with the animation.
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index c509980..6de1579 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -26,6 +26,7 @@
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
@@ -618,7 +619,8 @@
// If there was a recents animation in progress, cancel that animation
if (mService.getRecentsAnimationController() != null) {
- mService.getRecentsAnimationController().cancelAnimation();
+ mService.getRecentsAnimationController().cancelAnimation(
+ REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
}
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f1cd46b..28a57f5a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2687,20 +2687,20 @@
}
}
- public void cancelRecentsAnimation() {
+ public void cancelRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
// Note: Do not hold the WM lock, this will lock appropriately in the call which also
// calls through to AM/RecentsAnimation.onAnimationFinished()
if (mRecentsAnimationController != null) {
// This call will call through to cleanupAnimation() below after the animation is
// canceled
- mRecentsAnimationController.cancelAnimation();
+ mRecentsAnimationController.cancelAnimation(reorderMode);
}
}
- public void cleanupRecentsAnimation(boolean moveHomeToTop) {
+ public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
synchronized (mWindowMap) {
if (mRecentsAnimationController != null) {
- mRecentsAnimationController.cleanupAnimation(moveHomeToTop);
+ mRecentsAnimationController.cleanupAnimation(reorderMode);
mRecentsAnimationController = null;
mAppTransition.updateBooster();
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 54c2e9b..f015889 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -178,6 +178,7 @@
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -1366,6 +1367,7 @@
// Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
if (dc != null) {
mLayoutSeq = dc.mLayoutSeq - 1;
+ mInputWindowHandle.displayId = dc.getDisplayId();
}
}
@@ -1378,7 +1380,7 @@
public int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
- return -1;
+ return Display.INVALID_DISPLAY;
}
return displayContent.getDisplayId();
}
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 7765387..6290ff1 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -649,7 +649,7 @@
assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
null));
- assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation());
+ assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
}
private void testGetTasksApis(boolean expectCallable) {
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 92cc537..45bee6e 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -30,9 +30,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
import android.database.ContentObserver;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
+import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.os.BatteryManager;
import android.os.Handler;
@@ -571,6 +573,19 @@
assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA);
}
+ @Test
+ public void testNonNullAmbientStats() {
+ // getAmbientBrightnessStats should return an empty list rather than null when
+ // tracker isn't started or hasn't collected any data.
+ ParceledListSlice<AmbientBrightnessDayStats> slice = mTracker.getAmbientBrightnessStats(0);
+ assertNotNull(slice);
+ assertTrue(slice.getList().isEmpty());
+ startTracker(mTracker);
+ slice = mTracker.getAmbientBrightnessStats(0);
+ assertNotNull(slice);
+ assertTrue(slice.getList().isEmpty());
+ }
+
private InputStream getInputStream(String data) {
return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 2bfe274..6019958 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -159,6 +159,11 @@
}
@Override
+ public boolean shouldDeferStartOnMoveToFullscreen() {
+ return true;
+ }
+
+ @Override
public boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds) {
// TODO: Once we break the runs apart, we should fail() here if this is called outside
// of onAnimationStart() and onAnimationEnd()
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 1248eae..7c928c9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -326,6 +326,17 @@
assertThat(app.mLayoutSeq, not(is(mDisplayContent.mLayoutSeq)));
}
+ @Test
+ public void testDisplayIdUpdatedOnReparent() throws Exception {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ // fake a different display
+ app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
+ app.onDisplayChanged(mDisplayContent);
+
+ assertThat(app.mInputWindowHandle.displayId, is(mDisplayContent.getDisplayId()));
+ assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
+ }
+
private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
reset(mPowerManagerWrapper);
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 0815876..54ed1e6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -1093,7 +1093,7 @@
NotificationChannel channel2 =
new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel3 =
- new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG, UID, channel, true, false);
mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
@@ -1106,6 +1106,24 @@
}
@Test
+ public void testGetBlockedChannelCount() throws Exception {
+ NotificationChannel channel =
+ new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ NotificationChannel channel2 =
+ new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE);
+ NotificationChannel channel3 =
+ new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE);
+ mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+ mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
+ mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
+
+ mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
+
+ assertEquals(1, mHelper.getBlockedChannelCount(PKG, UID));
+ assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID2));
+ }
+
+ @Test
public void testCreateDeletedChannel() throws Exception {
long[] vibration = new long[]{100, 67, 145, 156};
NotificationChannel channel =