Merge "Request scroll capture when the screen rotates." into sc-dev
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index dc29c5e..a741f96 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -265,7 +265,7 @@
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "query");
+ traceBegin(TRACE_TAG_DATABASE, "query: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -285,7 +285,7 @@
// getCallingPackage() isn't available in getType(), as the javadoc states.
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- Trace.traceBegin(TRACE_TAG_DATABASE, "getType");
+ traceBegin(TRACE_TAG_DATABASE, "getType: ", uri.getAuthority());
try {
return mInterface.getType(uri);
} catch (RemoteException e) {
@@ -323,7 +323,7 @@
setCallingAttributionSource(original);
}
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
+ traceBegin(TRACE_TAG_DATABASE, "insert: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -345,7 +345,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
+ traceBegin(TRACE_TAG_DATABASE, "bulkInsert: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -391,7 +391,7 @@
}
}
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
+ traceBegin(TRACE_TAG_DATABASE, "applyBatch: ", authority);
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -423,7 +423,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
+ traceBegin(TRACE_TAG_DATABASE, "delete: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -445,7 +445,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return 0;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "update");
+ traceBegin(TRACE_TAG_DATABASE, "update: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -465,7 +465,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, mode);
- Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
+ traceBegin(TRACE_TAG_DATABASE, "openFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -486,7 +486,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, mode);
- Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
+ traceBegin(TRACE_TAG_DATABASE, "openAssetFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -505,7 +505,7 @@
String method, @Nullable String arg, @Nullable Bundle extras) {
validateIncomingAuthority(authority);
Bundle.setDefusable(extras, true);
- Trace.traceBegin(TRACE_TAG_DATABASE, "call");
+ traceBegin(TRACE_TAG_DATABASE, "call: ", authority);
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -523,7 +523,7 @@
// getCallingPackage() isn't available in getType(), as the javadoc states.
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes");
+ traceBegin(TRACE_TAG_DATABASE, "getStreamTypes: ", uri.getAuthority());
try {
return mInterface.getStreamTypes(uri, mimeTypeFilter);
} catch (RemoteException e) {
@@ -541,7 +541,7 @@
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
enforceFilePermission(attributionSource, uri, "r");
- Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
+ traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -569,7 +569,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return null;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
+ traceBegin(TRACE_TAG_DATABASE, "canonicalize: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -605,7 +605,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return null;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
+ traceBegin(TRACE_TAG_DATABASE, "uncanonicalize: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -641,7 +641,7 @@
!= PermissionChecker.PERMISSION_GRANTED) {
return false;
}
- Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
+ traceBegin(TRACE_TAG_DATABASE, "refresh: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -658,7 +658,7 @@
int uid, int modeFlags) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
+ traceBegin(TRACE_TAG_DATABASE, "checkUriPermission: ", uri.getAuthority());
final AttributionSource original = setCallingAttributionSource(
attributionSource);
try {
@@ -2683,4 +2683,10 @@
}
return uri;
}
+
+ private static void traceBegin(long traceTag, String methodName, String subInfo) {
+ if (Trace.isTagEnabled(traceTag)) {
+ Trace.traceBegin(traceTag, methodName + subInfo);
+ }
+ }
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index f3cc35b3..c5d0cd4 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -158,6 +158,8 @@
mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
"permissionmgr"));
mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class);
+ //TODO ntmyren: there should be a way to only enable the watcher when requested
+ mUsageHelper = new PermissionUsageHelper(context);
}
/**
@@ -878,10 +880,6 @@
@NonNull
@RequiresPermission(Manifest.permission.GET_APP_OPS_STATS)
public List<PermGroupUsage> getIndicatorAppOpUsageData() {
- // Lazily initialize the usage helper
- if (mUsageHelper == null) {
- mUsageHelper = new PermissionUsageHelper(mContext);
- }
return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute());
}
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 53ba259..d4e548e 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -19,6 +19,10 @@
import static android.Manifest.permission_group.CAMERA;
import static android.Manifest.permission_group.LOCATION;
import static android.Manifest.permission_group.MICROPHONE;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAGS_NONE;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER;
+import static android.app.AppOpsManager.AttributionFlags;
import static android.app.AppOpsManager.OPSTR_CAMERA;
import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION;
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
@@ -30,6 +34,7 @@
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -56,7 +61,7 @@
*
* @hide
*/
-public class PermissionUsageHelper {
+public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener {
/** Whether to show the mic and camera icons. */
private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled";
@@ -140,6 +145,7 @@
private ArrayMap<UserHandle, Context> mUserContexts;
private PackageManager mPkgManager;
private AppOpsManager mAppOpsManager;
+ private ArrayMap<Integer, ArrayList<AccessChainLink>> mAttributionChains = new ArrayMap<>();
/**
* Constructor for PermissionUsageHelper
@@ -151,6 +157,10 @@
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mUserContexts = new ArrayMap<>();
mUserContexts.put(Process.myUserHandle(), mContext);
+ // TODO ntmyren: make this listen for flag enable/disable changes
+ String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
+ mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops,
+ context.getMainExecutor(), this);
}
private Context getUserContext(UserHandle user) {
@@ -160,6 +170,45 @@
return mUserContexts.get(user);
}
+ @Override
+ public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
+ boolean active) {
+ // not part of an attribution chain. Do nothing
+ }
+
+ @Override
+ public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags,
+ int attributionChainId) {
+ if ((attributionFlags & ATTRIBUTION_FLAGS_NONE) != 0) {
+ return;
+ }
+
+ if (!active) {
+ // if any link in the chain is finished, remove the chain.
+ // TODO ntmyren: be smarter about this
+ mAttributionChains.remove(attributionChainId);
+ return;
+ }
+
+ ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent(
+ attributionChainId, k -> new ArrayList<>());
+ AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid,
+ attributionFlags);
+
+ int currSize = currentChain.size();
+ if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) {
+ // if the list is empty, this link is the end, or the last link in the current chain
+ // isn't the end, add it to the end
+ currentChain.add(link);
+ } else if (link.isStart()) {
+ currentChain.add(0, link);
+ } else if (currentChain.get(currentChain.size() - 1).isEnd()) {
+ // we already have the end, and this is a mid node, so insert before the end
+ currentChain.add(currSize - 1, link);
+ }
+ }
+
/**
* @see PermissionManager.getIndicatorAppOpUsageData
*/
@@ -331,7 +380,7 @@
private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) {
ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>();
- if (usages == null) {
+ if (usages == null || usages.isEmpty()) {
return usagesAndLabels;
}
@@ -430,8 +479,51 @@
}
iterNum++;
}
- usagesAndLabels.put(start,
- proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
+
+ // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource
+ // For now: don't add mic proxy usages
+ if (!start.op.equals(OPSTR_RECORD_AUDIO)) {
+ usagesAndLabels.put(start,
+ proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
+ }
+ }
+
+ for (int i = 0; i < mAttributionChains.size(); i++) {
+ List<AccessChainLink> usageList = mAttributionChains.valueAt(i);
+ int lastVisible = usageList.size() - 1;
+ // TODO ntmyren: remove this mic code once camera is converted to AttributionSource
+ // if the list is empty or incomplete, do not show it.
+ if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd()
+ || !usageList.get(0).isStart()
+ || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) {
+ continue;
+ }
+
+ //TODO ntmyren: remove once camera etc. etc.
+ for (AccessChainLink link: usageList) {
+ proxyPackages.add(link.usage.getPackageIdHash());
+ }
+
+ AccessChainLink start = usageList.get(0);
+ AccessChainLink lastVisibleLink = usageList.get(lastVisible);
+ while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) {
+ lastVisible--;
+ lastVisibleLink = usageList.get(lastVisible);
+ }
+ String proxyLabel = null;
+ if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) {
+ try {
+ PackageManager userPkgManager =
+ getUserContext(lastVisibleLink.usage.getUser()).getPackageManager();
+ ApplicationInfo appInfo = userPkgManager.getApplicationInfo(
+ lastVisibleLink.usage.packageName, 0);
+ proxyLabel = appInfo.loadLabel(userPkgManager).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ // do nothing
+ }
+
+ }
+ usagesAndLabels.put(start.usage, proxyLabel);
}
for (int packageHash : mostRecentUsages.keySet()) {
@@ -495,4 +587,24 @@
&& lastAccessTime == other.lastAccessTime && isRunning == other.isRunning;
}
}
+
+ private static class AccessChainLink {
+ public final OpUsage usage;
+ public final @AttributionFlags int flags;
+
+ AccessChainLink(String op, String packageName, String attributionTag, int uid,
+ int flags) {
+ this.usage = new OpUsage(packageName, attributionTag, op, uid,
+ System.currentTimeMillis(), true, null);
+ this.flags = flags;
+ }
+
+ public boolean isEnd() {
+ return (flags & ATTRIBUTION_FLAG_ACCESSOR) != 0;
+ }
+
+ public boolean isStart() {
+ return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0;
+ }
+ }
}
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 6a2b723..61f524f 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -154,4 +154,13 @@
* app.
*/
void detachNavigationBarFromApp(boolean moveHomeToTop);
+
+ /**
+ * Used for animating the navigation bar during app launch from recents in live tile mode.
+ *
+ * First fade out the navigation bar at the bottom of the display and then fade in to the app.
+ *
+ * @param duration the duration of the app launch animation
+ */
+ void animateNavigationBarToApp(long duration);
}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 40cce7c..d596626 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -44,6 +44,7 @@
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneId;
+import java.time.ZonedDateTime;
import java.util.Formatter;
import java.util.Locale;
@@ -451,7 +452,9 @@
if (mSecondHandTintInfo.mHasTintList || mSecondHandTintInfo.mHasTintBlendMode) {
mSecondHand = mSecondHandTintInfo.apply(mSecondHand);
}
- mSecondsTick.run();
+ // Re-run the tick runnable immediately as the presence or absence of a seconds hand affects
+ // the next time we need to tick the clock.
+ mTick.run();
mChanged = true;
invalidate();
@@ -583,10 +586,10 @@
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
// OK, this is gross but needed. This class is supported by the
- // remote views machanism and as a part of that the remote views
+ // remote views mechanism and as a part of that the remote views
// can be inflated by a context for another user without the app
// having interact users permission - just for loading resources.
- // For exmaple, when adding widgets from a user profile to the
+ // For example, when adding widgets from a user profile to the
// home screen. Therefore, we register the receiver as the current
// user not the one the context is for.
getContext().registerReceiverAsUser(mIntentReceiver,
@@ -616,14 +619,14 @@
private void onVisible() {
if (!mVisible) {
mVisible = true;
- mSecondsTick.run();
+ mTick.run();
}
}
private void onInvisible() {
if (mVisible) {
- removeCallbacks(mSecondsTick);
+ removeCallbacks(mTick);
mVisible = false;
}
}
@@ -760,6 +763,7 @@
}
}
+ /** Intent receiver for the time or time zone changing. */
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -767,36 +771,56 @@
createClock();
}
- onTimeChanged();
-
- invalidate();
+ mTick.run();
}
};
private boolean mReceiverAttached;
- private final Runnable mSecondsTick = new Runnable() {
+ private final Runnable mTick = new Runnable() {
@Override
public void run() {
removeCallbacks(this);
- if (!mVisible || mSecondHand == null) {
+ if (!mVisible) {
return;
}
Instant now = mClock.instant();
- LocalTime localTime = now.atZone(mClock.getZone()).toLocalTime();
- // How many milliseconds through the second we currently are.
- long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis();
- // How many milliseconds there are between tick positions for the seconds hand.
- double millisPerTick = 1000 / (double) mSecondsHandFps;
- // How many milliseconds we are past the last tick position.
- long millisPastLastTick = Math.round(millisOfSecond % millisPerTick);
- // How many milliseconds there are until the next tick position.
- long millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick);
- // If we are exactly at the tick position, this could be 0 milliseconds due to rounding.
- // In this case, advance by the full amount of millis to the next position.
- if (millisUntilNextTick <= 0) {
- millisUntilNextTick = Math.round(millisPerTick);
+ ZonedDateTime zonedDateTime = now.atZone(mClock.getZone());
+ LocalTime localTime = zonedDateTime.toLocalTime();
+
+ long millisUntilNextTick;
+ if (mSecondHand == null) {
+ // If there's no second hand, then tick at the start of the next minute.
+ //
+ // This must be done with ZonedDateTime as opposed to LocalDateTime to ensure proper
+ // handling of DST. Also note that because of leap seconds, it should not be assumed
+ // that one minute == 60 seconds.
+ Instant startOfNextMinute = zonedDateTime.plusMinutes(1).withSecond(0).toInstant();
+ millisUntilNextTick = Duration.between(now, startOfNextMinute).toMillis();
+ if (millisUntilNextTick <= 0) {
+ // This should never occur, but if it does, then just check the tick again in
+ // one minute to ensure we're always moving forward.
+ millisUntilNextTick = Duration.ofMinutes(1).toMillis();
+ }
+ } else {
+ // If there is a seconds hand, then determine the next tick point based on the fps.
+ //
+ // How many milliseconds through the second we currently are.
+ long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis();
+ // How many milliseconds there are between tick positions for the seconds hand.
+ double millisPerTick = 1000 / (double) mSecondsHandFps;
+ // How many milliseconds we are past the last tick position.
+ long millisPastLastTick = Math.round(millisOfSecond % millisPerTick);
+ // How many milliseconds there are until the next tick position.
+ millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick);
+ // If we are exactly at the tick position, this could be 0 milliseconds due to
+ // rounding. In this case, advance by the full amount of millis to the next
+ // position.
+ if (millisUntilNextTick <= 0) {
+ millisUntilNextTick = Math.round(millisPerTick);
+ }
}
+
// Schedule a callback for when the next tick should occur.
postDelayed(this, millisUntilNextTick);
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index b1485ef..e48afb2 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -34,7 +34,6 @@
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.DateFormat;
@@ -45,6 +44,10 @@
import com.android.internal.R;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.TimeZone;
@@ -185,18 +188,29 @@
private final Runnable mTicker = new Runnable() {
public void run() {
- if (mStopTicking) {
+ removeCallbacks(this);
+ if (mStopTicking || !mShouldRunTicker) {
return; // Test disabled the clock ticks
}
onTimeChanged();
- long now = SystemClock.uptimeMillis();
- long next = now + (1000 - now % 1000);
+ Instant now = mTime.toInstant();
+ ZoneId zone = mTime.getTimeZone().toZoneId();
- Handler handler = getHandler();
- if (handler != null) {
- handler.postAtTime(mTicker, next);
+ ZonedDateTime nextTick;
+ if (mHasSeconds) {
+ nextTick = now.atZone(zone).plusSeconds(1).withNano(0);
+ } else {
+ nextTick = now.atZone(zone).plusMinutes(1).withSecond(0).withNano(0);
}
+
+ long millisUntilNextTick = Duration.between(now, nextTick.toInstant()).toMillis();
+ if (millisUntilNextTick <= 0) {
+ // This should never happen, but if it does, then tick again in a second.
+ millisUntilNextTick = 1000;
+ }
+
+ postDelayed(this, millisUntilNextTick);
}
};
@@ -519,8 +533,7 @@
mHasSeconds = DateFormat.hasSeconds(mFormat);
if (mShouldRunTicker && hadSeconds != mHasSeconds) {
- if (hadSeconds) getHandler().removeCallbacks(mTicker);
- else mTicker.run();
+ mTicker.run();
}
}
@@ -557,14 +570,10 @@
if (!mShouldRunTicker && isVisible) {
mShouldRunTicker = true;
- if (mHasSeconds) {
- mTicker.run();
- } else {
- onTimeChanged();
- }
+ mTicker.run();
} else if (mShouldRunTicker && !isVisible) {
mShouldRunTicker = false;
- getHandler().removeCallbacks(mTicker);
+ removeCallbacks(mTicker);
}
}
@@ -592,7 +601,6 @@
private void registerReceiver() {
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a64129e..756425e 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -293,4 +293,7 @@
be able to connect to the internet when such a proxy is in use, since
all outgoing connections originate from this app. -->
<allow-in-power-save-except-idle package="com.android.proxyhandler" />
+
+ <!-- Allow IMS service entitlement app to schedule jobs to run when app in background. -->
+ <allow-in-power-save-except-idle package="com.android.imsserviceentitlement" />
</permissions>
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index 10df726..8881be7 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -19,7 +19,7 @@
package="com.android.wm.shell">
<!-- System permission required by WM Shell Task Organizer. -->
<uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
</manifest>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index a88be31..f7fb63d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -46,6 +46,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.startingsurface.StartingWindowController;
@@ -55,6 +56,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Unified task organizer for all components in the shell.
@@ -342,6 +344,19 @@
notifySizeCompatUI(info.getTaskInfo(), listener);
}
+ /**
+ * Take a screenshot of a task.
+ */
+ public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+ final TaskAppearedInfo info = mTasks.get(taskInfo.taskId);
+ if (info == null) {
+ return;
+ }
+ ScreenshotUtils.captureLayer(info.getLeash(), crop, consumer);
+ }
+
+
@Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
synchronized (mLock) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 2fc696c..35a4f33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -231,7 +231,8 @@
* Fade animation for consecutive flyouts.
*/
void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
- boolean hideDot) {
+ boolean hideDot, Runnable onHide) {
+ mOnHide = onHide;
final Runnable afterFadeOut = () -> {
updateFlyoutMessage(flyoutMessage, parentWidth);
// Wait for TextViews to layout with updated height.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index d821c6f..8613dcb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1492,22 +1492,22 @@
mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
}
- if (getBubbleCount() == 0) {
- mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
- }
-
if (bubble.getIconView() == null) {
return;
}
+ mBubbleContainer.addView(bubble.getIconView(), 0,
+ new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
+ mPositioner.getBubbleSize()));
+
+ if (getBubbleCount() == 0) {
+ mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
+ }
// Set the dot position to the opposite of the side the stack is resting on, since the stack
// resting slightly off-screen would result in the dot also being off-screen.
bubble.getIconView().setDotBadgeOnLeft(!mStackOnLeftOrWillBe /* onLeft */);
bubble.getIconView().setOnClickListener(mBubbleClickListener);
bubble.getIconView().setOnTouchListener(mBubbleTouchListener);
- mBubbleContainer.addView(bubble.getIconView(), 0,
- new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
- mPositioner.getBubbleSize()));
updateBubbleShadows(false /* showForAllBubbles */);
animateInFlyoutForBubble(bubble);
requestUpdate();
@@ -2400,7 +2400,8 @@
if (mFlyout.getVisibility() == View.VISIBLE) {
mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
- mStackAnimationController.getStackPosition(), !bubble.showDot());
+ mStackAnimationController.getStackPosition(), !bubble.showDot(),
+ mAfterFlyoutHidden /* onHide */);
} else {
mFlyout.setVisibility(INVISIBLE);
mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
@@ -2408,7 +2409,7 @@
mStackAnimationController.isStackOnLeftSide(),
bubble.getIconView().getDotColor() /* dotColor */,
expandFlyoutAfterDelay /* onLayoutComplete */,
- mAfterFlyoutHidden,
+ mAfterFlyoutHidden /* onHide */,
bubble.getIconView().getDotCenter(),
!bubble.showDot(),
mPositioner);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 8043d2b..12d55b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -124,9 +124,6 @@
*/
private Rect mAnimatingToBounds = new Rect();
- /** Initial starting location for the stack. */
- @Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;
-
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
index 32575fa..eea6e3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
@@ -21,6 +21,8 @@
import android.graphics.Rect;
import android.view.SurfaceControl;
+import java.util.function.Consumer;
+
/**
* Helpers for working with screenshots.
*/
@@ -29,6 +31,60 @@
/**
* Take a screenshot of the specified SurfaceControl.
*
+ * @param sc the SurfaceControl to take a screenshot of
+ * @param crop the crop to use when capturing the screenshot
+ * @param consumer Consumer for the captured buffer
+ */
+ public static void captureLayer(SurfaceControl sc, Rect crop,
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+ consumer.accept(SurfaceControl.captureLayers(
+ new SurfaceControl.LayerCaptureArgs.Builder(sc)
+ .setSourceCrop(crop)
+ .setCaptureSecureLayers(true)
+ .setAllowProtected(true)
+ .build()));
+ }
+
+ private static class BufferConsumer implements
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> {
+ SurfaceControl mScreenshot = null;
+ SurfaceControl.Transaction mTransaction;
+ SurfaceControl mSurfaceControl;
+ int mLayer;
+
+ BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) {
+ mTransaction = t;
+ mSurfaceControl = sc;
+ mLayer = layer;
+ }
+
+ @Override
+ public void accept(SurfaceControl.ScreenshotHardwareBuffer buffer) {
+ if (buffer == null || buffer.getHardwareBuffer() == null) {
+ return;
+ }
+ final GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
+ buffer.getHardwareBuffer());
+ mScreenshot = new SurfaceControl.Builder()
+ .setName("ScreenshotUtils screenshot")
+ .setFormat(PixelFormat.TRANSLUCENT)
+ .setSecure(buffer.containsSecureLayers())
+ .setCallsite("ScreenshotUtils.takeScreenshot")
+ .setBLASTLayer()
+ .build();
+
+ mTransaction.setBuffer(mScreenshot, graphicBuffer);
+ mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
+ mTransaction.reparent(mScreenshot, mSurfaceControl);
+ mTransaction.setLayer(mScreenshot, mLayer);
+ mTransaction.show(mScreenshot);
+ mTransaction.apply();
+ }
+ }
+
+ /**
+ * Take a screenshot of the specified SurfaceControl.
+ *
* @param t the transaction used to set changes on the resulting screenshot.
* @param sc the SurfaceControl to take a screenshot of
* @param crop the crop to use when capturing the screenshot
@@ -38,32 +94,8 @@
*/
public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
Rect crop, int layer) {
- final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
- new SurfaceControl.LayerCaptureArgs.Builder(sc)
- .setSourceCrop(crop)
- .setCaptureSecureLayers(true)
- .setAllowProtected(true)
- .build()
- );
- if (buffer == null || buffer.getHardwareBuffer() == null) {
- return null;
- }
- final GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
- buffer.getHardwareBuffer());
- final SurfaceControl screenshot = new SurfaceControl.Builder()
- .setName("ScreenshotUtils screenshot")
- .setFormat(PixelFormat.TRANSLUCENT)
- .setSecure(buffer.containsSecureLayers())
- .setCallsite("ScreenshotUtils.takeScreenshot")
- .setBLASTLayer()
- .build();
-
- t.setBuffer(screenshot, graphicBuffer);
- t.setColorSpace(screenshot, buffer.getColorSpace());
- t.reparent(screenshot, sc);
- t.setLayer(screenshot, layer);
- t.show(screenshot);
- t.apply();
- return screenshot;
+ BufferConsumer consumer = new BufferConsumer(t, sc, layer);
+ captureLayer(sc, crop, consumer);
+ return consumer.mScreenshot;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 7d032ad..afd7d26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -628,8 +628,10 @@
final Rect destinationBounds = mPipBoundsState.getBounds();
final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
- mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
- mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
+ mSurfaceTransactionHelper
+ .resetScale(tx, mLeash, destinationBounds)
+ .crop(tx, mLeash, destinationBounds)
+ .round(tx, mLeash, isInPip());
// The animation is finished in the Launcher and here we directly apply the final touch.
applyEnterPipSyncTransaction(destinationBounds, () -> {
// Ensure menu's settled in its final bounds first.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 51a67e2..bf1f9e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -60,6 +60,7 @@
import java.util.function.Consumer;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
/**
* Util class to create the view for a splash screen content.
@@ -207,6 +208,15 @@
.build();
}
+ private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) {
+ try {
+ return getMethod.apply(def);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Get attribute fail, return default: " + e.getMessage());
+ return def;
+ }
+ }
+
/**
* Get the {@link SplashScreenWindowAttrs} from {@code context} and fill them into
* {@code attrs}.
@@ -215,16 +225,18 @@
final TypedArray typedArray = context.obtainStyledAttributes(
com.android.internal.R.styleable.Window);
attrs.mWindowBgResId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
- attrs.mWindowBgColor = typedArray.getColor(
- R.styleable.Window_windowSplashScreenBackground, Color.TRANSPARENT);
- attrs.mReplaceIcon = typedArray.getDrawable(
- R.styleable.Window_windowSplashScreenAnimatedIcon);
- attrs.mAnimationDuration = typedArray.getInt(
- R.styleable.Window_windowSplashScreenAnimationDuration, 0);
- attrs.mBrandingImage = typedArray.getDrawable(
- R.styleable.Window_windowSplashScreenBrandingImage);
- attrs.mIconBgColor = typedArray.getColor(
- R.styleable.Window_windowSplashScreenIconBackgroundColor, Color.TRANSPARENT);
+ attrs.mWindowBgColor = safeReturnAttrDefault((def) -> typedArray.getColor(
+ R.styleable.Window_windowSplashScreenBackground, def),
+ Color.TRANSPARENT);
+ attrs.mReplaceIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable(
+ R.styleable.Window_windowSplashScreenAnimatedIcon), null);
+ attrs.mAnimationDuration = safeReturnAttrDefault((def) -> typedArray.getInt(
+ R.styleable.Window_windowSplashScreenAnimationDuration, def), 0);
+ attrs.mBrandingImage = safeReturnAttrDefault((def) -> typedArray.getDrawable(
+ R.styleable.Window_windowSplashScreenBrandingImage), null);
+ attrs.mIconBgColor = safeReturnAttrDefault((def) -> typedArray.getColor(
+ R.styleable.Window_windowSplashScreenIconBackgroundColor, def),
+ Color.TRANSPARENT);
typedArray.recycle();
if (DEBUG) {
Slog.d(TAG, "window attributes color: "
@@ -476,9 +488,14 @@
drawable = layerDrawable.getDrawable(0);
}
}
- mColorChecker = drawable instanceof ColorDrawable
- ? new SingleColorTester((ColorDrawable) drawable)
- : new ComplexDrawableTester(drawable, filterTransparent);
+ if (drawable == null) {
+ mColorChecker = new SingleColorTester(
+ (ColorDrawable) createDefaultBackgroundDrawable());
+ } else {
+ mColorChecker = drawable instanceof ColorDrawable
+ ? new SingleColorTester((ColorDrawable) drawable)
+ : new ComplexDrawableTester(drawable, filterTransparent);
+ }
}
public float nonTransparentRatio() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java
index fbbd09f..ad9dda6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelper.java
@@ -16,6 +16,13 @@
package com.android.wm.shell.tasksurfacehelper;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
/**
* Interface to communicate with a Task's SurfaceControl.
*/
@@ -23,4 +30,8 @@
/** Sets the METADATA_GAME_MODE for the layer corresponding to the task **/
default void setGameModeForTask(int taskId, int gameMode) {}
+
+ /** Takes a screenshot for a task **/
+ default void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Executor executor,
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java
index b459b9f..064d9d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/tasksurfacehelper/TaskSurfaceHelperController.java
@@ -16,11 +16,16 @@
package com.android.wm.shell.tasksurfacehelper;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.graphics.Rect;
import android.view.SurfaceControl;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ShellExecutor;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
/**
* Intermediary controller that communicates with {@link ShellTaskOrganizer} to send commands
* to SurfaceControl.
@@ -49,6 +54,14 @@
mTaskOrganizer.setSurfaceMetadata(taskId, SurfaceControl.METADATA_GAME_MODE, gameMode);
}
+ /**
+ * Take screenshot of the specified task.
+ */
+ public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+ mTaskOrganizer.screenshotTask(taskInfo, crop, consumer);
+ }
+
private class TaskSurfaceHelperImpl implements TaskSurfaceHelper {
@Override
public void setGameModeForTask(int taskId, int gameMode) {
@@ -56,5 +69,14 @@
TaskSurfaceHelperController.this.setGameModeForTask(taskId, gameMode);
});
}
+
+ @Override
+ public void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Executor executor,
+ Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+ mMainExecutor.execute(() -> {
+ TaskSurfaceHelperController.this.screenshotTask(taskInfo, crop,
+ (t) -> executor.execute(() -> consumer.accept(t)));
+ });
+ }
}
}
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 01a2ec5..fe9a30a 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -429,7 +429,9 @@
kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr);
if (bufferInfo->skSurface.get() == nullptr) {
ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
- mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd.release());
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
+ mNativeBuffers[idx].dequeue_fence.release());
+ mNativeBuffers[idx].dequeued = false;
return nullptr;
}
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index cb56ee5..a3842a1 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -178,6 +178,7 @@
public static final int POWER_HIGH = 203;
private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
+ private static final double IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 6D;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ "LocationManager} methods to provide the provider explicitly.")
@@ -552,7 +553,7 @@
*/
public @IntRange(from = 0) long getMinUpdateIntervalMillis() {
if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
- return mInterval;
+ return (long) (mInterval * IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR);
} else {
// the min is only necessary in case someone use a deprecated function to mess with the
// interval or min update interval
@@ -1018,7 +1019,9 @@
* Sets an explicit minimum update interval. If location updates are available faster than
* the request interval then an update will only occur if the minimum update interval has
* expired since the last location update. Defaults to no explicit minimum update interval
- * set, which means the minimum update interval is the same as the interval.
+ * set, which means some sensible default between 0 and the interval will be chosen. The
+ * exact value is not specified at the moment. If an exact known value is required, clients
+ * should set an explicit value themselves.
*
* <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
* minimum update interval, so you need not worry about updates blocked simply because they
@@ -1037,7 +1040,8 @@
/**
* Clears an explicitly set minimum update interval and reverts to an implicit minimum
- * update interval (ie, the minimum update interval is the same value as the interval).
+ * update interval (ie, the minimum update interval is some sensible default between 0 and
+ * the interval).
*/
public @NonNull Builder clearMinUpdateIntervalMillis() {
mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
index a39e779..e74ac44 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
@@ -33,7 +33,7 @@
<style name="Banner.Title.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
index 579abbd5..23aa993 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
@@ -42,7 +42,7 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
index 2c2756b..2c35772 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout-v31/preference_two_target.xml
@@ -40,7 +40,7 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
diff --git a/packages/SettingsLib/res/layout/preference_access_point.xml b/packages/SettingsLib/res/layout/preference_access_point.xml
index f3f43ac..802d604 100644
--- a/packages/SettingsLib/res/layout/preference_access_point.xml
+++ b/packages/SettingsLib/res/layout/preference_access_point.xml
@@ -64,7 +64,7 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
diff --git a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
index e4f7242..f512f9b 100644
--- a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
@@ -61,7 +61,7 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
index d9f91de..169ae97 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_preference.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -51,7 +51,7 @@
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
index 5dbcb79..1520ac8 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -16,11 +16,11 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/restricted_icon"
- android:layout_width="@*android:dimen/config_restrictedIconSize"
+ android:layout_width="@dimen/two_target_min_width"
android:layout_height="@*android:dimen/config_restrictedIconSize"
android:tint="?android:attr/colorAccent"
android:src="@*android:drawable/ic_info"
- android:gravity="end|center_vertical" />
+ android:gravity="center" />
<!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/switch_widget"
diff --git a/packages/SystemUI/res/drawable/people_space_activity_card.xml b/packages/SystemUI/res/drawable/people_space_activity_card.xml
index 338bff8..7e2db63 100644
--- a/packages/SystemUI/res/drawable/people_space_activity_card.xml
+++ b/packages/SystemUI/res/drawable/people_space_activity_card.xml
@@ -14,5 +14,5 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?android:attr/colorBackgroundFloating" />
+ <solid android:color="@color/people_tile_background" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_content_background.xml b/packages/SystemUI/res/drawable/people_space_content_background.xml
index 30519ae..9704871 100644
--- a/packages/SystemUI/res/drawable/people_space_content_background.xml
+++ b/packages/SystemUI/res/drawable/people_space_content_background.xml
@@ -15,6 +15,6 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="@color/people_tile_background" />
<corners android:radius="@dimen/people_space_image_radius" />
</shape>
diff --git a/packages/SystemUI/res/drawable/people_space_new_story_outline.xml b/packages/SystemUI/res/drawable/people_space_new_story_outline.xml
index a1737f9..4d6249d 100644
--- a/packages/SystemUI/res/drawable/people_space_new_story_outline.xml
+++ b/packages/SystemUI/res/drawable/people_space_new_story_outline.xml
@@ -15,6 +15,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="@color/people_tile_background" />
<stroke android:width="2dp" android:color="?android:attr/colorAccent" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_rounded_border.xml b/packages/SystemUI/res/drawable/people_space_rounded_border.xml
index 9956bc2..50560df 100644
--- a/packages/SystemUI/res/drawable/people_space_rounded_border.xml
+++ b/packages/SystemUI/res/drawable/people_space_rounded_border.xml
@@ -15,5 +15,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="@color/people_tile_background" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_tile_view_card.xml b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
index 8fd4388..6e1e5de 100644
--- a/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
+++ b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
@@ -14,6 +14,6 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?android:attr/colorBackground" />
+ <solid android:color="@color/people_tile_background" />
<corners android:radius="@dimen/people_space_widget_radius" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_tile_empty_background.xml b/packages/SystemUI/res/drawable/people_tile_empty_background.xml
index 2dac740..7dbea73 100644
--- a/packages/SystemUI/res/drawable/people_tile_empty_background.xml
+++ b/packages/SystemUI/res/drawable/people_tile_empty_background.xml
@@ -14,8 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <solid android:color="?androidprv:attr/colorSurface" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/people_tile_background" />
<corners android:radius="@dimen/people_space_widget_radius" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index c473229..8e6293a 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -97,4 +97,6 @@
<!-- Accessibility floating menu -->
<color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
+
+ <color name="people_tile_background">@android:color/system_accent2_800</color>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f64299d..2cf3058 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -281,4 +281,6 @@
<!-- Wallet screen -->
<color name="wallet_card_border">#33FFFFFF</color>
+
+ <color name="people_tile_background">@android:color/system_accent2_50</color>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 74aa138..fb9aa4a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -46,12 +46,13 @@
mTmpSourceRectF.set(sourceBounds);
mTmpDestinationRectF.set(destinationBounds);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+ final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top)
- .setCornerRadius(leash, mCornerRadius);
+ .setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
mTmpDestinationRectF.left, mTmpDestinationRectF.top,
- mTmpFloat9, 0 /* rotation */, mCornerRadius, sourceBounds);
+ mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scale(
@@ -62,11 +63,12 @@
mTmpDestinationRectF.set(destinationBounds);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
mTmpTransform.postRotate(degree, 0, 0);
+ final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
- .setCornerRadius(leash, mCornerRadius);
+ .setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, degree, mCornerRadius, sourceBounds);
+ positionX, positionY, mTmpFloat9, degree, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scaleAndCrop(
@@ -83,12 +85,15 @@
final float left = destinationBounds.left - insets.left * scale;
final float top = destinationBounds.top - insets.top * scale;
mTmpTransform.setScale(scale, scale);
+ final Rect cornerRadiusRect = new Rect(destinationBounds);
+ cornerRadiusRect.inset(insets);
+ final float cornerRadius = getScaledCornerRadius(sourceBounds, cornerRadiusRect);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, left, top)
- .setCornerRadius(leash, mCornerRadius);
+ .setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
- left, top, mTmpFloat9, 0 /* rotation */, mCornerRadius, mTmpDestinationRect);
+ left, top, mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
}
public PictureInPictureSurfaceTransaction scaleAndRotate(
@@ -105,12 +110,22 @@
: (float) destinationBounds.height() / sourceBounds.height();
mTmpTransform.setRotate(degree, 0, 0);
mTmpTransform.postScale(scale, scale);
+ final Rect cornerRadiusRect = new Rect(destinationBounds);
+ cornerRadiusRect.inset(insets);
+ final float cornerRadius = getScaledCornerRadius(sourceBounds, cornerRadiusRect);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, positionX, positionY)
- .setCornerRadius(leash, mCornerRadius);
+ .setCornerRadius(leash, cornerRadius);
return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, degree, mCornerRadius, mTmpDestinationRect);
+ positionX, positionY, mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
+ }
+
+ /** @return the round corner radius scaled by given from and to bounds */
+ private float getScaledCornerRadius(Rect fromBounds, Rect toBounds) {
+ final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
+ / Math.hypot(toBounds.width(), toBounds.height()));
+ return mCornerRadius * scale;
}
/** @return {@link SurfaceControl.Transaction} instance with vsync-id */
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 700ec49..8e65560 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
@@ -152,4 +152,15 @@
Log.e(TAG, "Failed to detach the navigation bar from app", e);
}
}
+
+ /**
+ * @see IRecentsAnimationController#animateNavigationBarToApp(long)
+ */
+ public void animateNavigationBarToApp(long duration) {
+ try {
+ mAnimationController.animateNavigationBarToApp(duration);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to animate the navigation bar to app", e);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 619bf1b..92ffb42 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -64,9 +64,10 @@
private float mDarkAmount;
/**
- * Boolean value indicating if notifications are visible on lock screen.
+ * Boolean value indicating if notifications are visible on lock screen. Use null to signify
+ * it is uninitialized.
*/
- private boolean mHasVisibleNotifications = true;
+ private Boolean mHasVisibleNotifications = null;
private AnimatorSet mClockInAnim = null;
private AnimatorSet mClockOutAnim = null;
@@ -263,7 +264,8 @@
* the smaller version.
*/
boolean willSwitchToLargeClock(boolean hasVisibleNotifications) {
- if (hasVisibleNotifications == mHasVisibleNotifications) {
+ if (mHasVisibleNotifications != null
+ && hasVisibleNotifications == mHasVisibleNotifications) {
return false;
}
boolean useLargeClock = !hasVisibleNotifications;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index fcb090a..717c715 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -66,6 +66,7 @@
import java.io.PrintWriter;
import java.text.NumberFormat;
+import java.util.Collections;
import java.util.Locale;
/**
@@ -178,7 +179,13 @@
// Initialize listeners.
mMirrorViewRunnable = () -> {
if (mMirrorView != null) {
+ final Rect oldViewBounds = new Rect(mMirrorViewBounds);
mMirrorView.getBoundsOnScreen(mMirrorViewBounds);
+ if (oldViewBounds.width() != mMirrorViewBounds.width()
+ || oldViewBounds.height() != mMirrorViewBounds.height()) {
+ mMirrorView.setSystemGestureExclusionRects(Collections.singletonList(
+ new Rect(0, 0, mMirrorViewBounds.width(), mMirrorViewBounds.height())));
+ }
updateSystemUIStateIfNeeded();
mWindowMagnifierCallback.onWindowMagnifierBoundsChanged(
mDisplayId, mMirrorViewBounds);
@@ -269,6 +276,7 @@
if (mMirrorWindowControl != null) {
mMirrorWindowControl.destroyControl();
}
+ mMirrorViewBounds.setEmpty();
updateSystemUIStateIfNeeded();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index ca59393..76fb49a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -130,19 +130,29 @@
@Override
public void onAuthenticationFailed(
@Modality int modality, @Nullable String failureReason) {
- if (modality == TYPE_FACE && mActiveSensorType == TYPE_FACE) {
- // switching from face -> fingerprint mode, suppress soft error messages
- failureReason = mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead);
+ super.onAuthenticationFailed(modality, checkErrorForFallback(failureReason));
+ }
+
+ @Override
+ public void onError(int modality, String error) {
+ super.onError(modality, checkErrorForFallback(error));
+ }
+
+ private String checkErrorForFallback(String message) {
+ if (mActiveSensorType == TYPE_FACE) {
+ Log.d(TAG, "Falling back to fingerprint: " + message);
+
+ // switching from face -> fingerprint mode, suppress root error messages
+ mCallback.onAction(Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR);
+ return mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead);
}
- super.onAuthenticationFailed(modality, failureReason);
+ return message;
}
@Override
@BiometricState
protected int getStateForAfterError() {
if (mActiveSensorType == TYPE_FACE) {
- mHandler.post(() -> mCallback.onAction(
- Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
return STATE_AUTHENTICATING;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index f7b3a35..085a076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -26,6 +26,8 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -53,6 +55,11 @@
private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
private static final String TAG = "NotificationShelf";
+ // More extreme version of SLOW_OUT_LINEAR_IN which keeps the icon nearly invisible until after
+ // the next icon has translated out of the way, to avoid overlapping.
+ private static final Interpolator ICON_ALPHA_INTERPOLATOR =
+ new PathInterpolator(0.6f, 0f, 0.6f, 0f);
+
private NotificationIconContainer mShelfIcons;
private int[] mTmp = new int[2];
private boolean mHideBackground;
@@ -659,7 +666,7 @@
if (iconState == null) {
return;
}
- iconState.alpha = transitionAmount;
+ iconState.alpha = ICON_ALPHA_INTERPOLATOR.getInterpolation(transitionAmount);
boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
iconState.hidden = isAppearing
|| (view instanceof ExpandableNotificationRow
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 9390c81..2c2a170 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2097,11 +2097,13 @@
if (height != 0) {
height += mPaddingBetweenElements;
}
- height += calculateGapHeight(previousView, expandableView, numShownItems);
+ float gapHeight = calculateGapHeight(previousView, expandableView, numShownNotifs);
+ height += gapHeight;
height += viewHeight;
numShownItems++;
- if (!(expandableView instanceof MediaHeaderView)) {
+ if (viewHeight > 0 || !(expandableView instanceof MediaHeaderView)) {
+ // Only count the media as a notification if it has a positive height.
numShownNotifs++;
}
previousView = expandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index fda24c1..e2d64b09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -139,6 +139,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.notification.stack.MediaHeaderView;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -1325,21 +1326,27 @@
ExpandableView previousView = null;
for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
- if (!(child instanceof ExpandableNotificationRow)) {
- continue;
- }
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean
- suppressedSummary =
- mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
- row.getEntry().getSbn());
- if (suppressedSummary) {
- continue;
- }
- if (!canShowViewOnLockscreen(child)) {
- continue;
- }
- if (row.isRemoved()) {
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ boolean suppressedSummary = mGroupManager != null
+ && mGroupManager.isSummaryOfSuppressedGroup(row.getEntry().getSbn());
+ if (suppressedSummary) {
+ continue;
+ }
+ if (!canShowViewOnLockscreen(child)) {
+ continue;
+ }
+ if (row.isRemoved()) {
+ continue;
+ }
+ } else if (child instanceof MediaHeaderView) {
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ if (child.getIntrinsicHeight() == 0) {
+ continue;
+ }
+ } else {
continue;
}
availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index d61848c..e0ff88b 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -75,6 +75,10 @@
static final String COLOR_SOURCE_PRESET = "preset";
+ static final String COLOR_SOURCE_HOME = "home_wallpaper";
+
+ static final String COLOR_SOURCE_LOCK = "lock_wallpaper";
+
static final String TIMESTAMP_FIELD = "_applied_timestamp";
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index c23e0b4..428921e 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -16,6 +16,8 @@
package com.android.systemui.theme;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
+import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
+import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
@@ -200,36 +202,37 @@
String overlayPackageJson = mSecureSettings.getStringForUser(
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
currentUser);
- boolean isDestinationBoth = mWallpaperManager.getWallpaperId(
- WallpaperManager.FLAG_LOCK) < 0;
- if (!TextUtils.isEmpty(overlayPackageJson)) {
- try {
- JSONObject jsonObject = new JSONObject(overlayPackageJson);
- if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
- && ((flags & latestWallpaperType) != 0)) {
- mSkipSettingChange = true;
- if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
- OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
- jsonObject.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
- jsonObject.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
- jsonObject.remove(OVERLAY_COLOR_SOURCE);
- jsonObject.remove(OVERLAY_COLOR_INDEX);
- }
- // Keep color_both value because users can change either or both home and
- // lock screen wallpapers.
- jsonObject.put(OVERLAY_COLOR_BOTH, isDestinationBoth ? "1" : "0");
-
- jsonObject.put(TIMESTAMP_FIELD, System.currentTimeMillis());
- if (DEBUG) {
- Log.d(TAG, "Updating theme setting from "
- + overlayPackageJson + " to " + jsonObject.toString());
- }
- mSecureSettings.putString(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
- jsonObject.toString());
+ boolean isDestinationBoth = (flags == (WallpaperManager.FLAG_SYSTEM
+ | WallpaperManager.FLAG_LOCK));
+ try {
+ JSONObject jsonObject = (overlayPackageJson == null) ? new JSONObject()
+ : new JSONObject(overlayPackageJson);
+ if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
+ && ((flags & latestWallpaperType) != 0)) {
+ mSkipSettingChange = true;
+ if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
+ OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
+ jsonObject.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
+ jsonObject.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
+ jsonObject.remove(OVERLAY_COLOR_INDEX);
}
- } catch (JSONException e) {
- Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
+ // Keep color_both value because users can change either or both home and
+ // lock screen wallpapers.
+ jsonObject.put(OVERLAY_COLOR_BOTH, isDestinationBoth ? "1" : "0");
+
+ jsonObject.put(OVERLAY_COLOR_SOURCE,
+ (flags == WallpaperManager.FLAG_LOCK) ? COLOR_SOURCE_LOCK
+ : COLOR_SOURCE_HOME);
+ jsonObject.put(TIMESTAMP_FIELD, System.currentTimeMillis());
+ if (DEBUG) {
+ Log.d(TAG, "Updating theme setting from "
+ + overlayPackageJson + " to " + jsonObject.toString());
+ }
+ mSecureSettings.putString(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+ jsonObject.toString());
}
+ } catch (JSONException e) {
+ Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
}
reevaluateSystemTheme(false /* forceReload */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index ad99e4d..f62069d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -77,6 +77,8 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@LargeTest
@RunWith(AndroidTestingRunner.class)
public class WindowMagnificationControllerTest extends SysuiTestCase {
@@ -152,6 +154,19 @@
}
@Test
+ public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+ // Wait for Rects updated.
+ waitForIdleSync();
+
+ List<Rect> rects = mWindowManager.getAttachedView().getSystemGestureExclusionRects();
+ assertFalse(rects.isEmpty());
+ }
+
+ @Test
public void deleteWindowMagnification_destroyControl() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index aed0da6..82bf041 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -22,6 +22,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -124,16 +126,50 @@
}
@Test
- public void testModeUpdated_whenSwitchToFingerprint() {
+ public void testModeUpdated_onSoftError_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
waitForIdleSync();
verify(mIndicatorView).setText(
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
+ verify(mCallback).onAction(
+ eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
}
+ @Test
+ public void testModeUpdated_onHardError_whenSwitchToFingerprint() {
+ mFaceToFpView.onDialogAnimatedIn();
+ mFaceToFpView.onError(TYPE_FACE, "oh no!");
+ waitForIdleSync();
+
+ verify(mIndicatorView).setText(
+ eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
+ verify(mCallback).onAction(
+ eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+ }
+
+ @Test
+ public void testFingerprintOnlyStartsOnFirstError() {
+ mFaceToFpView.onDialogAnimatedIn();
+ verify(mFaceToFpView.mIconController)
+ .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+
+ mFaceToFpView.onDialogAnimatedIn();
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+
+ reset(mCallback);
+
+ mFaceToFpView.onError(TYPE_FACE, "oh no!");
+ mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
+
+ verify(mCallback, never()).onAction(
+ eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
+ }
+
public class TestableView extends AuthBiometricFaceToFingerprintView {
public TestableView(Context context) {
super(context, null, new MockInjector());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3d2a0f1..3cf9212 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -232,9 +232,9 @@
verify(mSecureSettings).putString(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
- assertThat(updatedSetting.getValue().contains("android.theme.customization.system_palette"))
+ assertThat(updatedSetting.getValue().contains("android.theme.customization.accent_color"))
.isFalse();
- assertThat(updatedSetting.getValue().contains("android.theme.customization.color_source"))
+ assertThat(updatedSetting.getValue().contains("android.theme.customization.system_palette"))
.isFalse();
assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
.isFalse();
@@ -289,7 +289,8 @@
.thenReturn(jsonString);
when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(-1);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors,
+ WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -303,6 +304,60 @@
}
@Test
+ public void onWallpaperColorsChanged_changeLockWallpaper() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.system_palette\":\"override.package.name\","
+ + "\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
+ assertThat(updatedSetting.getValue().contains(
+ "android.theme.customization.color_source\":\"lock_wallpaper")).isTrue();
+ assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
+ .isFalse();
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_changeHomeWallpaper() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.system_palette\":\"override.package.name\","
+ + "\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(-1);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
+ assertThat(updatedSetting.getValue().contains(
+ "android.theme.customization.color_source\":\"home_wallpaper")).isTrue();
+ assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
+ .isFalse();
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onWallpaperColorsChanged_ResetThemeWhenFromLatestWallpaper() {
// Should ask for a new theme when the colors of the last applied wallpaper change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c994d7c..c841fa3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5996,13 +5996,23 @@
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name, int userId,
boolean stable) {
- return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable);
+ traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getContentProvider: ", name);
+ try {
+ return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
@Override
public ContentProviderHolder getContentProviderExternal(
String name, int userId, IBinder token, String tag) {
- return mCpHelper.getContentProviderExternal(name, userId, token, tag);
+ traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getContentProviderExternal: ", name);
+ try {
+ return mCpHelper.getContentProviderExternal(name, userId, token, tag);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
/**
@@ -6017,18 +6027,57 @@
@Deprecated
@Override
public void removeContentProviderExternal(String name, IBinder token) {
- removeContentProviderExternalAsUser(name, token, UserHandle.getCallingUserId());
+ traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "removeContentProviderExternal: ", name);
+ try {
+ removeContentProviderExternalAsUser(name, token, UserHandle.getCallingUserId());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
@Override
public void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
- mCpHelper.removeContentProviderExternalAsUser(name, token, userId);
+ traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "removeContentProviderExternalAsUser: ", name);
+ try {
+ mCpHelper.removeContentProviderExternalAsUser(name, token, userId);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
@Override
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
- mCpHelper.publishContentProviders(caller, providers);
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ final int maxLength = 256;
+ final StringBuilder sb = new StringBuilder(maxLength);
+ sb.append("publishContentProviders: ");
+ if (providers != null) {
+ boolean first = true;
+ for (int i = 0, size = providers.size(); i < size; i++) {
+ final ContentProviderHolder holder = providers.get(i);
+ if (holder != null && holder.info != null && holder.info.authority != null) {
+ final int len = holder.info.authority.length();
+ if (sb.length() + len > maxLength) {
+ sb.append("[[TRUNCATED]]");
+ break;
+ }
+ if (!first) {
+ sb.append(';');
+ } else {
+ first = false;
+ }
+ sb.append(holder.info.authority);
+ }
+ }
+ }
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, sb.toString());
+ }
+ try {
+ mCpHelper.publishContentProviders(caller, providers);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
@Override
@@ -17108,4 +17157,10 @@
SystemClock.sleep(durationMs);
}
}
+
+ static void traceBegin(long traceTag, String methodName, String subInfo) {
+ if (Trace.isTagEnabled(traceTag)) {
+ Trace.traceBegin(traceTag, methodName + subInfo);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index ab1da80..1611395 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -58,6 +58,7 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -707,20 +708,28 @@
mService.enforceNotIsolatedCaller("removeContentProvider");
final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mService) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection) connection;
- } catch (ClassCastException e) {
- String msg = "removeContentProvider: " + connection
- + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "removeContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+ ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "removeContentProvider: ",
+ (conn.provider != null && conn.provider.info != null
+ ? conn.provider.info.authority : ""));
+ try {
+ synchronized (mService) {
+ decProviderCountLocked(conn, null, null, stable, true, true);
}
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
- decProviderCountLocked(conn, null, null, stable, true, true);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -781,8 +790,15 @@
throw new NullPointerException("connection is null");
}
- conn.adjustCounts(stable, unstable);
- return !conn.dead;
+ ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "refContentProvider: ",
+ (conn.provider != null && conn.provider.info != null
+ ? conn.provider.info.authority : ""));
+ try {
+ conn.adjustCounts(stable, unstable);
+ return !conn.dead;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
void unstableProviderDied(IBinder connection) {
@@ -798,50 +814,60 @@
throw new NullPointerException("connection is null");
}
- // Safely retrieve the content provider associated with the connection.
- IContentProvider provider;
- synchronized (mService) {
- provider = conn.provider.provider;
- }
+ ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "unstableProviderDied: ",
+ (conn.provider != null && conn.provider.info != null
+ ? conn.provider.info.authority : ""));
- if (provider == null) {
- // Um, yeah, we're way ahead of you.
- return;
- }
-
- // Make sure the caller is being honest with us.
- if (provider.asBinder().pingBinder()) {
- // Er, no, still looks good to us.
+ try {
+ // Safely retrieve the content provider associated with the connection.
+ IContentProvider provider;
synchronized (mService) {
- Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
- + " says " + conn + " died, but we don't agree");
- return;
+ provider = conn.provider.provider;
}
- }
- // Well look at that! It's dead!
- synchronized (mService) {
- if (conn.provider.provider != provider) {
- // But something changed... good enough.
+ if (provider == null) {
+ // Um, yeah, we're way ahead of you.
return;
}
- ProcessRecord proc = conn.provider.proc;
- if (proc == null || proc.getThread() == null) {
- // Seems like the process is already cleaned up.
- return;
+ // Make sure the caller is being honest with us.
+ if (provider.asBinder().pingBinder()) {
+ // Er, no, still looks good to us.
+ synchronized (mService) {
+ Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
+ + " says " + conn + " died, but we don't agree");
+ return;
+ }
}
- // As far as we're concerned, this is just like receiving a
- // death notification... just a bit prematurely.
- mService.reportUidInfoMessageLocked(TAG, "Process " + proc.processName
- + " (pid " + proc.getPid() + ") early provider death", proc.info.uid);
- final long token = Binder.clearCallingIdentity();
- try {
- mService.appDiedLocked(proc, "unstable content provider");
- } finally {
- Binder.restoreCallingIdentity(token);
+ // Well look at that! It's dead!
+ synchronized (mService) {
+ if (conn.provider.provider != provider) {
+ // But something changed... good enough.
+ return;
+ }
+
+ ProcessRecord proc = conn.provider.proc;
+ if (proc == null || proc.getThread() == null) {
+ // Seems like the process is already cleaned up.
+ return;
+ }
+
+ // As far as we're concerned, this is just like receiving a
+ // death notification... just a bit prematurely.
+ mService.reportUidInfoMessageLocked(TAG, "Process " + proc.processName
+ + " (pid " + proc.getPid() + ") early provider death",
+ proc.info.uid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.appDiedLocked(proc, "unstable content provider");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -855,13 +881,21 @@
return;
}
- final ProcessRecord host = conn.provider.proc;
- if (host == null) {
- Slog.w(TAG, "Failed to find hosting ProcessRecord");
- return;
- }
+ ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "appNotRespondingViaProvider: ",
+ (conn.provider != null && conn.provider.info != null
+ ? conn.provider.info.authority : ""));
+ try {
+ final ProcessRecord host = conn.provider.proc;
+ if (host == null) {
+ Slog.w(TAG, "Failed to find hosting ProcessRecord");
+ return;
+ }
- mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");
+ mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
}
/**
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 55128be..c2259eb 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -84,8 +84,8 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
-import android.app.AppOpsManager.AttributionFlags;
import android.app.AppOpsManager.AttributedOpEntry;
+import android.app.AppOpsManager.AttributionFlags;
import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.Mode;
import android.app.AppOpsManager.OpEntry;
@@ -3255,13 +3255,6 @@
shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
}
- // TODO b/184963112: remove once full blaming is implemented
- private boolean isRecognitionServiceTemp(int code, String packageName) {
- return code == OP_RECORD_AUDIO
- && (packageName.equals("com.google.android.googlequicksearchbox")
- || packageName.equals("com.google.android.tts"));
- }
-
private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
boolean skipProxyOperation) {
@@ -3289,8 +3282,7 @@
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isSelfBlame
- || isRecognitionServiceTemp(code, proxyPackageName);
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame;
if (!skipProxyOperation) {
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 36dc5cd..ef02a47 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -355,10 +355,6 @@
}
}
- private void cancelAllFingerprintSensors() {
- cancelAllSensors(sensor -> sensor.modality == TYPE_FINGERPRINT);
- }
-
private void cancelAllSensors() {
cancelAllSensors(sensor -> true);
}
@@ -387,6 +383,9 @@
*/
boolean onErrorReceived(int sensorId, int cookie, @BiometricConstants.Errors int error,
int vendorCode) throws RemoteException {
+ if (DEBUG) {
+ Slog.v(TAG, "onErrorReceived sensor: " + sensorId + " error: " + error);
+ }
if (!containsCookie(cookie)) {
Slog.e(TAG, "Unknown/expired cookie: " + cookie);
@@ -454,12 +453,14 @@
// a round trip to SystemUI.
mClientReceiver.onError(modality, error, vendorCode);
return true;
- } else if (shouldErrorTriggerMultiSensorTransition()) {
- // wait for the UI to signal when modality should switch
- mMultiSensorState = MULTI_SENSOR_STATE_SWITCHING;
- Slog.d(TAG, "onErrorReceived: waiting for modality switch callback");
} else {
mState = STATE_ERROR_PENDING_SYSUI;
+ if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT
+ && mMultiSensorState == MULTI_SENSOR_STATE_FACE_SCANNING) {
+ // wait for the UI to signal when modality should switch
+ Slog.d(TAG, "onErrorReceived: waiting for modality switch callback");
+ mMultiSensorState = MULTI_SENSOR_STATE_SWITCHING;
+ }
mStatusBarService.onBiometricError(modality, error, vendorCode);
}
break;
@@ -627,7 +628,7 @@
void onDeviceCredentialPressed() {
// Cancel authentication. Skip the token/package check since we are cancelling
// from system server. The interface is permission protected so this is fine.
- cancelBiometricOnly();
+ cancelAllSensors();
mState = STATE_SHOWING_DEVICE_CREDENTIAL;
}
@@ -733,12 +734,10 @@
}
mClientReceiver.onAuthenticationSucceeded(
Utils.getAuthenticationTypeForResult(reason));
- cancelBiometricOnly();
break;
case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
mClientReceiver.onDialogDismissed(reason);
- cancelBiometricOnly();
break;
case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
@@ -747,7 +746,6 @@
BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
0 /* vendorCode */
);
- cancelBiometricOnly();
break;
case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
@@ -765,6 +763,9 @@
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
+ } finally {
+ // ensure everything is cleaned up when dismissed
+ cancelAllSensors();
}
}
@@ -780,8 +781,8 @@
|| mState == STATE_AUTH_STARTED
|| mState == STATE_AUTH_STARTED_UI_SHOWING;
+ cancelAllSensors();
if (authStarted && !force) {
- cancelAllSensors();
// Wait for ERROR_CANCELED to be returned from the sensors
return false;
} else {
@@ -804,22 +805,6 @@
return false;
}
- /**
- * Cancels biometric authentication only. AuthSession may either be going into
- * {@link #STATE_SHOWING_DEVICE_CREDENTIAL} or dismissed.
- */
- private void cancelBiometricOnly() {
- if (mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED_UI_SHOWING) {
- cancelAllSensors();
- } else if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
- cancelAllFingerprintSensors();
- } else {
- if (DEBUG) {
- Slog.v(TAG, "nothing to cancel - wrong state: " + mState);
- }
- }
- }
-
boolean isCrypto() {
return mOperationId != 0;
}
@@ -896,13 +881,6 @@
}
}
- private boolean shouldErrorTriggerMultiSensorTransition() {
- if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
- return mMultiSensorState == MULTI_SENSOR_STATE_FACE_SCANNING;
- }
- return false;
- }
-
@BiometricMultiSensorMode
private static int getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors) {
boolean hasFace = false;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b0f8ee1..92b6a08 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -5495,7 +5495,8 @@
final int result = checkPermission(mContext, permission, attributionSource, message,
forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
// Finish any started op if some step in the attribution chain failed.
- if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) {
+ if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED
+ && result != PermissionChecker.PERMISSION_SOFT_DENIED) {
if (attributedOp == AppOpsManager.OP_NONE) {
finishDataDelivery(AppOpsManager.permissionToOpCode(permission),
attributionSource.asState(), fromDatasource);
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index e5a634f..b6b8ad1 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -128,12 +128,9 @@
if (w == null || winHint != null && w != winHint) {
return;
}
- final boolean surfaceReady = w.isDrawn() // Regular case
- || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
- final boolean needsLetterbox = surfaceReady && shouldShowLetterboxUi(w);
updateRoundedCorners(w);
updateWallpaperForLetterbox(w);
- if (needsLetterbox) {
+ if (shouldShowLetterboxUi(w)) {
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null),
mActivityRecord.mWmService.mTransactionFactory,
@@ -161,19 +158,26 @@
}
}
- /**
- * @return {@code true} when the main window is letterboxed, this activity isn't transparent
- * and doesn't show a wallpaper.
- */
@VisibleForTesting
boolean shouldShowLetterboxUi(WindowState mainWindow) {
- return mainWindow.areAppWindowBoundsLetterboxed() && mActivityRecord.fillsParent()
+ return isSurfaceReadyAndVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed()
+ // Check that an activity isn't transparent.
+ && mActivityRecord.fillsParent()
// Check for FLAG_SHOW_WALLPAPER explicitly instead of using
// WindowContainer#showWallpaper because the later will return true when this
// activity is using blurred wallpaper for letterbox backgroud.
&& (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
}
+ @VisibleForTesting
+ boolean isSurfaceReadyAndVisible(WindowState mainWindow) {
+ boolean surfaceReady = mainWindow.isDrawn() // Regular case
+ // Waiting for relayoutWindow to call preserveSurface
+ || mainWindow.isDragResizeChanged();
+ return surfaceReady && (mActivityRecord.isVisible()
+ || mActivityRecord.isVisibleRequested());
+ }
+
private Color getLetterboxBackgroundColor() {
final WindowState w = mActivityRecord.findMainWindow();
if (w == null || w.isLetterboxedForDisplayCutout()) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 2b40b75..5362771 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -156,6 +156,7 @@
@VisibleForTesting
boolean mShouldAttachNavBarToAppDuringTransition;
private boolean mNavigationBarAttachedToApp;
+ private ActivityRecord mNavBarAttachedApp;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
@@ -392,6 +393,18 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public void animateNavigationBarToApp(long duration) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService.getWindowManagerLock()) {
+ animateNavigationBarForAppLaunch(duration);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
/**
@@ -613,7 +626,6 @@
|| mDisplayContent.getFadeRotationAnimationController() != null) {
return;
}
- ActivityRecord topActivity = null;
boolean shouldTranslateNavBar = false;
final boolean isDisplayLandscape =
mDisplayContent.getConfiguration().orientation == ORIENTATION_LANDSCAPE;
@@ -630,12 +642,12 @@
continue;
}
shouldTranslateNavBar = isSplitScreenSecondary;
- topActivity = task.getTopVisibleActivity();
+ mNavBarAttachedApp = task.getTopVisibleActivity();
break;
}
final WindowState navWindow = getNavigationBarWindow();
- if (topActivity == null || navWindow == null || navWindow.mToken == null) {
+ if (mNavBarAttachedApp == null || navWindow == null || navWindow.mToken == null) {
return;
}
mNavigationBarAttachedToApp = true;
@@ -643,9 +655,9 @@
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
if (shouldTranslateNavBar) {
- navWindow.setSurfaceTranslationY(-topActivity.getBounds().top);
+ navWindow.setSurfaceTranslationY(-mNavBarAttachedApp.getBounds().top);
}
- t.reparent(navSurfaceControl, topActivity.getSurfaceControl());
+ t.reparent(navSurfaceControl, mNavBarAttachedApp.getSurfaceControl());
t.show(navSurfaceControl);
final WindowContainer imeContainer = mDisplayContent.getImeContainer();
@@ -695,9 +707,25 @@
}
}
+ void animateNavigationBarForAppLaunch(long duration) {
+ if (!mShouldAttachNavBarToAppDuringTransition
+ // Skip the case where the nav bar is controlled by fade rotation.
+ || mDisplayContent.getFadeRotationAnimationController() != null
+ || mNavigationBarAttachedToApp
+ || mNavBarAttachedApp == null) {
+ return;
+ }
+
+ final NavBarFadeAnimationController controller =
+ new NavBarFadeAnimationController(mDisplayContent);
+ controller.fadeOutAndInSequentially(duration, null /* fadeOutParent */,
+ mNavBarAttachedApp.getSurfaceControl());
+ }
+
void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) {
if (mRunner != null) {
mIsAddingTaskToTargets = task != null;
+ mNavBarAttachedApp = task == null ? null : task.getTopVisibleActivity();
// No need to send task appeared when the task target already exists, or when the
// task is being managed as a multi-window mode outside of recents (e.g. bubbles).
if (isAnimatingTask(task) || skipAnimation(task)) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b754644..e13ef99 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1987,43 +1987,39 @@
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
jobject jLights = env->NewObject(gArrayListClassInfo.clazz, gArrayListClassInfo.constructor);
- std::vector<int> lightIds = im->getInputManager()->getReader()->getLightIds(deviceId);
+ std::vector<InputDeviceLightInfo> lights =
+ im->getInputManager()->getReader()->getLights(deviceId);
- for (size_t i = 0; i < lightIds.size(); i++) {
- const InputDeviceLightInfo* lightInfo =
- im->getInputManager()->getReader()->getLightInfo(deviceId, lightIds[i]);
- if (lightInfo == nullptr) {
- ALOGW("Failed to get input device %d light info for id %d", deviceId, lightIds[i]);
- continue;
- }
+ for (size_t i = 0; i < lights.size(); i++) {
+ const InputDeviceLightInfo& lightInfo = lights[i];
jint jTypeId =
env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeInput);
jint jCapability = 0;
- if (lightInfo->type == InputDeviceLightType::MONO) {
+ if (lightInfo.type == InputDeviceLightType::MONO) {
jCapability = env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightCapabilityBrightness);
- } else if (lightInfo->type == InputDeviceLightType::RGB ||
- lightInfo->type == InputDeviceLightType::MULTI_COLOR) {
+ } else if (lightInfo.type == InputDeviceLightType::RGB ||
+ lightInfo.type == InputDeviceLightType::MULTI_COLOR) {
jCapability =
env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightCapabilityBrightness) |
env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightCapabilityRgb);
- } else if (lightInfo->type == InputDeviceLightType::PLAYER_ID) {
+ } else if (lightInfo.type == InputDeviceLightType::PLAYER_ID) {
jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
gLightClassInfo.lightTypePlayerId);
} else {
- ALOGW("Unknown light type %d", lightInfo->type);
+ ALOGW("Unknown light type %d", lightInfo.type);
continue;
}
ScopedLocalRef<jobject> lightObj(env,
env->NewObject(gLightClassInfo.clazz,
gLightClassInfo.constructor,
- static_cast<jint>(lightInfo->id),
- env->NewStringUTF(lightInfo->name.c_str()),
- static_cast<jint>(lightInfo->ordinal),
+ static_cast<jint>(lightInfo.id),
+ env->NewStringUTF(lightInfo.name.c_str()),
+ static_cast<jint>(lightInfo.ordinal),
jTypeId, jCapability));
// Add light object to list
env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
@@ -2218,39 +2214,28 @@
static jobjectArray nativeGetSensorList(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- std::vector<InputDeviceInfo> devices = im->getInputManager()->getReader()->getInputDevices();
- // Find the input device by deviceId
- auto it = std::find_if(devices.begin(), devices.end(),
- [deviceId](InputDeviceInfo& info) { return info.getId() == deviceId; });
+ std::vector<InputDeviceSensorInfo> sensors =
+ im->getInputManager()->getReader()->getSensors(deviceId);
- if (it == devices.end()) {
- // Return an array of size 0
- return env->NewObjectArray(0, gInputSensorInfo.clazz, nullptr);
- }
+ jobjectArray arr = env->NewObjectArray(sensors.size(), gInputSensorInfo.clazz, nullptr);
+ for (int i = 0; i < sensors.size(); i++) {
+ const InputDeviceSensorInfo& sensorInfo = sensors[i];
- std::vector<InputDeviceSensorType> types = it->getSensorTypes();
- jobjectArray arr = env->NewObjectArray(types.size(), gInputSensorInfo.clazz, nullptr);
- for (int i = 0; i < types.size(); i++) {
- const InputDeviceSensorInfo* sensorInfo = it->getSensorInfo(types[i]);
- if (sensorInfo == nullptr) {
- ALOGW("Failed to get input device %d sensor info for type %s", deviceId,
- NamedEnum::string(types[i]).c_str());
- continue;
- }
-
- jobject info =
- createInputSensorInfo(env, env->NewStringUTF(sensorInfo->name.c_str()),
- env->NewStringUTF(sensorInfo->vendor.c_str()),
- (jint)sensorInfo->version, 0 /* handle */,
- (jint)sensorInfo->type, (jfloat)sensorInfo->maxRange,
- (jfloat)sensorInfo->resolution, (jfloat)sensorInfo->power,
- (jfloat)sensorInfo->minDelay,
- (jint)sensorInfo->fifoReservedEventCount,
- (jint)sensorInfo->fifoMaxEventCount,
- env->NewStringUTF(sensorInfo->stringType.c_str()),
- env->NewStringUTF("") /* requiredPermission */,
- (jint)sensorInfo->maxDelay, (jint)sensorInfo->flags,
- (jint)sensorInfo->id);
+ jobject info = createInputSensorInfo(env, env->NewStringUTF(sensorInfo.name.c_str()),
+ env->NewStringUTF(sensorInfo.vendor.c_str()),
+ static_cast<jint>(sensorInfo.version), 0 /* handle */,
+ static_cast<jint>(sensorInfo.type),
+ static_cast<jfloat>(sensorInfo.maxRange),
+ static_cast<jfloat>(sensorInfo.resolution),
+ static_cast<jfloat>(sensorInfo.power),
+ static_cast<jfloat>(sensorInfo.minDelay),
+ static_cast<jint>(sensorInfo.fifoReservedEventCount),
+ static_cast<jint>(sensorInfo.fifoMaxEventCount),
+ env->NewStringUTF(sensorInfo.stringType.c_str()),
+ env->NewStringUTF("") /* requiredPermission */,
+ static_cast<jint>(sensorInfo.maxDelay),
+ static_cast<jint>(sensorInfo.flags),
+ static_cast<jint>(sensorInfo.id));
env->SetObjectArrayElement(arr, i, info);
env->DeleteLocalRef(info);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
index 7148ed4..ce9fa2d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
@@ -68,7 +68,7 @@
notifyCallbackOnError(
InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
"The battery level must be above "
- + mConstants.BATTERY_THRESHOLD_NOT_CHARGING + " while not charging or"
+ + mConstants.BATTERY_THRESHOLD_NOT_CHARGING + " while not charging or "
+ "above " + mConstants.BATTERY_THRESHOLD_CHARGING + " while charging");
return;
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 4afb7dd..2892bf5 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -18,6 +18,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE;
import static com.android.server.biometrics.BiometricServiceStateProto.*;
@@ -38,7 +39,6 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.Context;
-import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricAuthenticator;
@@ -67,6 +67,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
+import java.util.function.Consumer;
@Presubmit
@SmallTest
@@ -245,9 +246,6 @@
assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
assertEquals(BiometricSensor.STATE_COOKIE_RETURNED,
session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState());
- session.onErrorReceived(fingerprintSensorId,
- session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getCookie(),
- BiometricConstants.BIOMETRIC_ERROR_VENDOR, 0 /* vendorCode */);
session.onStartFingerprint();
}
assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
@@ -258,6 +256,21 @@
@Test
public void testCancelAuthentication_whenStateAuthCalled_invokesCancel()
throws RemoteException {
+ testInvokesCancel(session -> session.onCancelAuthSession(false /* force */));
+ }
+
+ @Test
+ public void testCancelAuthentication_whenStateAuthForcedCalled_invokesCancel()
+ throws RemoteException {
+ testInvokesCancel(session -> session.onCancelAuthSession(true /* force */));
+ }
+
+ @Test
+ public void testCancelAuthentication_whenDialogDismissed() throws RemoteException {
+ testInvokesCancel(session -> session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null));
+ }
+
+ private void testInvokesCancel(Consumer<AuthSession> sessionConsumer) throws RemoteException {
final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
@@ -269,7 +282,8 @@
session.goToInitialState();
assertEquals(STATE_AUTH_CALLED, session.getState());
- session.onCancelAuthSession(false /* force */);
+
+ sessionConsumer.accept(session);
verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE));
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index ae836ce..7c7afb7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -1036,7 +1036,7 @@
}
@Test
- public void testDismissedReasonNegative_whilePaused_doesntInvokeHalCancel() throws Exception {
+ public void testDismissedReasonNegative_whilePaused_invokeHalCancel() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */);
@@ -1050,14 +1050,12 @@
BiometricPrompt.DISMISSED_REASON_NEGATIVE, null /* credentialAttestation */);
waitForIdle();
- verify(mBiometricService.mSensors.get(0).impl,
- never()).cancelAuthenticationFromService(
- any(),
- any());
+ verify(mBiometricService.mSensors.get(0).impl)
+ .cancelAuthenticationFromService(any(), any());
}
@Test
- public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws
+ public void testDismissedReasonUserCancel_whilePaused_invokesHalCancel() throws
Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
@@ -1072,10 +1070,8 @@
BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
waitForIdle();
- verify(mBiometricService.mSensors.get(0).impl,
- never()).cancelAuthenticationFromService(
- any(),
- any());
+ verify(mBiometricService.mSensors.get(0).impl)
+ .cancelAuthenticationFromService(any(), any());
}
@Test
@@ -1091,11 +1087,8 @@
BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
waitForIdle();
- // doesn't send cancel to HAL
- verify(mBiometricService.mSensors.get(0).impl,
- never()).cancelAuthenticationFromService(
- any(),
- any());
+ verify(mBiometricService.mSensors.get(0).impl)
+ .cancelAuthenticationFromService(any(), any());
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index db7e437..d2270b5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -50,6 +50,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.same;
@@ -357,6 +358,11 @@
final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window");
assertEquals(window, mActivity.findMainWindow());
+
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .isSurfaceReadyAndVisible(any());
+
assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi(
mActivity.findMainWindow()));
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 0bb09a9..3182501 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -131,6 +131,17 @@
protected long getAutoDisconnectTimeoutMs() {
return -1;
}
+
+ @Override
+ public void binderDied() {
+ super.binderDied();
+ Slog.w(TAG, "binderDied");
+ try {
+ callback.onError(-1);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to report onError status: " + e);
+ }
+ }
};
mRemoteHotwordDetectionService.connect();
if (callback == null) {
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 4d5b6ac..88efe1f 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1069,6 +1069,13 @@
*/
public static final int NO_DEFAULT_DATA = 0x10008;
+ /**
+ * Data service is temporarily unavailable.
+ *
+ * @hide
+ */
+ public static final int SERVICE_TEMPORARILY_UNAVAILABLE = 0x10009;
+
private static final Map<Integer, String> sFailCauseMap;
static {
sFailCauseMap = new HashMap<>();
@@ -1500,6 +1507,7 @@
sFailCauseMap.put(HANDOVER_FAILED, "HANDOVER_FAILED");
sFailCauseMap.put(DUPLICATE_CID, "DUPLICATE_CID");
sFailCauseMap.put(NO_DEFAULT_DATA, "NO_DEFAULT_DATA");
+ sFailCauseMap.put(SERVICE_TEMPORARILY_UNAVAILABLE, "SERVICE_TEMPORARILY_UNAVAILABLE");
}
private DataFailCause() {
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 363e47a..d082715 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -63,6 +63,11 @@
public static final int RESULT_ERROR_BUSY = 3;
/** Request sent in illegal state */
public static final int RESULT_ERROR_ILLEGAL_STATE = 4;
+ /**
+ * Service is temporarily unavailable. Frameworks should retry the request again.
+ * @hide
+ */
+ public static final int RESULT_ERROR_TEMPORARILY_UNAVAILABLE = 5;
private final IDataServiceCallback mCallback;