Merge "Report touchable region changes to Accessibility." into pi-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index 5cffd0e..f1c6120 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -564,6 +564,11 @@
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ method public int[] getCapabilities();
+ method public int[] getTransportTypes();
+ }
+
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -897,6 +902,14 @@
}
+package android.telecom {
+
+ public final class CallAudioState implements android.os.Parcelable {
+ ctor public CallAudioState(boolean, int, int, android.bluetooth.BluetoothDevice, java.util.Collection<android.bluetooth.BluetoothDevice>);
+ }
+
+}
+
package android.telephony {
public class MbmsDownloadSession implements java.lang.AutoCloseable {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index df8763c..136fd14 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -87,7 +87,8 @@
mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
StatsdStats::kAtomDimensionKeySizeLimitMap.end()
? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
- : StatsdStats::kDimensionKeySizeHardLimit) {
+ : StatsdStats::kDimensionKeySizeHardLimit),
+ mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()) {
// TODO: valuemetric for pushed events may need unlimited bucket length
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
@@ -393,15 +394,20 @@
}
} else {
// Generally we expect value to be monotonically increasing.
- // If not, there was a reset event. We take the absolute value as
- // diff in this case.
+ // If not, take absolute value or drop it, based on config.
if (interval.startUpdated) {
if (value >= interval.start) {
interval.sum += (value - interval.start);
+ interval.hasValue = true;
} else {
- interval.sum += value;
+ if (mUseAbsoluteValueOnReset) {
+ interval.sum += value;
+ interval.hasValue = true;
+ } else {
+ VLOG("Dropping data for atom %d, prev: %lld, now: %lld", mPullTagId,
+ (long long)interval.start, (long long)value);
+ }
}
- interval.hasValue = true;
interval.startUpdated = false;
} else {
VLOG("No start for matching end %lld", (long long)value);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 113be4b..0136ec1 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -164,6 +164,8 @@
const size_t mDimensionHardLimit;
+ const bool mUseAbsoluteValueOnReset;
+
FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 849d5f6..eb77299 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -265,6 +265,8 @@
optional AggregationType aggregation_type = 8 [default = SUM];
optional int64 min_bucket_size_nanos = 10;
+
+ optional bool use_absolute_value_on_reset = 11 [default = false];
}
message Alert {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9e3a1ca..7ecfbe6 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -3208,8 +3208,6 @@
Landroid/net/NetworkCapabilities;-><init>()V
Landroid/net/NetworkCapabilities;->addCapability(I)Landroid/net/NetworkCapabilities;
Landroid/net/NetworkCapabilities;->addTransportType(I)Landroid/net/NetworkCapabilities;
-Landroid/net/NetworkCapabilities;->getCapabilities()[I
-Landroid/net/NetworkCapabilities;->getTransportTypes()[I
Landroid/net/NetworkCapabilities;->mNetworkCapabilities:J
Landroid/net/NetworkCapabilities;->mSignalStrength:I
Landroid/net/NetworkCapabilities;->removeCapability(I)Landroid/net/NetworkCapabilities;
@@ -6664,6 +6662,7 @@
Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
Landroid/widget/RemoteViews;->mLayoutId:I
Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews;
+Landroid/widget/RemoteViews;->setIsWidgetCollectionChild(Z)V
Landroid/widget/RemoteViews;->setRemoteAdapter(ILjava/util/ArrayList;I)V
Landroid/widget/RemoteViewsAdapter;->getRemoteViewsServiceIntent()Landroid/content/Intent;
Landroid/widget/RemoteViewsAdapter;->isDataReady()Z
@@ -8059,6 +8058,7 @@
Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List;
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Ldalvik/system/BaseDexClassLoader;-><init>(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;Ljava/lang/ClassLoader;Z)V
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3b62bd7..7b383d4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -979,7 +979,9 @@
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
- newBase.setAutofillClient(this);
+ if (newBase != null) {
+ newBase.setAutofillClient(this);
+ }
}
/** @hide */
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
new file mode 100644
index 0000000..24c5d23
--- /dev/null
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.util.SparseIntArray;
+
+/**
+ * App ops service local interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppOpsManagerInternal {
+ /**
+ * Set the currently configured device and profile owners. Specifies the package uid (value)
+ * that has been configured for each user (key) that has one. These will be allowed privileged
+ * access to app ops for their user.
+ */
+ public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
+}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ca3257f..9db642b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -700,7 +700,7 @@
librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null /* classLoaderName */);
StrictMode.setThreadPolicy(oldPolicy);
- mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
+ mAppComponentFactory = AppComponentFactory.DEFAULT;
}
return;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 1b05402..1b07784 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -513,7 +513,7 @@
try {
mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId());
} catch (RemoteException e) {
- // Nothing to do
+ throw e.rethrowFromSystemServer();
}
}
@@ -539,8 +539,8 @@
}
return bucketMap;
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return Collections.EMPTY_MAP;
}
/**
@@ -563,6 +563,7 @@
try {
mService.setAppStandbyBuckets(slice, mContext.getUserId());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -596,6 +597,7 @@
mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit),
callbackIntent, mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -614,6 +616,7 @@
try {
mService.unregisterAppUsageObserver(observerId, mContext.getOpPackageName());
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -698,6 +701,7 @@
try {
mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
} catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
@@ -709,6 +713,7 @@
try {
mService.onCarrierPrivilegedAppsChanged();
} catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 65dfb13..a808c64 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -427,6 +428,7 @@
* @return an array of capability values for this instance.
* @hide
*/
+ @TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
@@ -690,6 +692,7 @@
* @return an array of transport type values for this instance.
* @hide
*/
+ @TestApi
public @Transport int[] getTransportTypes() {
return BitUtils.unpackBits(mTransportTypes);
}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index d7c267b..d3d3874 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -143,4 +143,21 @@
void stopPrinterStateTracking(in PrinterId printerId, int userId);
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
int userId);
+
+ /**
+ * Check if the system will bind to print services in intant app.
+ *
+ * @param userId the Id of the user the behavior should be checked for
+ *
+ * @return {@code true} iff the system will bind to print services in instant apps.
+ */
+ boolean getBindInstantServiceAllowed(int userId);
+
+ /**
+ * Set if the system will bind to print services in intant app.
+ *
+ * @param userId the Id of the user the behavior should be changed for
+ * @param allows iff {@code true} the system will bind to print services in instant apps
+ */
+ void setBindInstantServiceAllowed(int userId, boolean allowed);
}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index d51a13f..f1e937e 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -644,9 +644,11 @@
if (osize <= 1) {
// Now empty.
if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
- freeArrays(mHashes, mArray, osize);
+ final int[] ohashes = mHashes;
+ final Object[] oarray = mArray;
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
+ freeArrays(ohashes, oarray, osize);
nsize = 0;
} else {
nsize = osize - 1;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3807079..049d34f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15049,8 +15049,7 @@
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
- float oldAlpha = mTransformationInfo.mAlpha;
- mTransformationInfo.mAlpha = alpha;
+ setAlphaInternal(alpha);
if (onSetAlpha((int) (alpha * 255))) {
mPrivateFlags |= PFLAG_ALPHA_SET;
// subclass is handling alpha - don't optimize rendering cache invalidation
@@ -15061,10 +15060,6 @@
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
}
- // Report visibility changes, which can affect children, to accessibility
- if ((alpha == 0) ^ (oldAlpha == 0)) {
- notifySubtreeAccessibilityStateChangedIfNeeded();
- }
}
}
@@ -15081,7 +15076,7 @@
boolean setAlphaNoInvalidation(float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
- mTransformationInfo.mAlpha = alpha;
+ setAlphaInternal(alpha);
boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
if (subclassHandlesAlpha) {
mPrivateFlags |= PFLAG_ALPHA_SET;
@@ -15094,6 +15089,15 @@
return false;
}
+ private void setAlphaInternal(float alpha) {
+ float oldAlpha = mTransformationInfo.mAlpha;
+ mTransformationInfo.mAlpha = alpha;
+ // Report visibility changes, which can affect children, to accessibility
+ if ((alpha == 0) ^ (oldAlpha == 0)) {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ }
+ }
+
/**
* This property is hidden and intended only for use by the Fade transition, which
* animates it to produce a visual translucency that does not side-effect (or get
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2ec42c0..65a6125 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -8574,6 +8574,8 @@
private final Rect mLocation = new Rect();
+ private ViewGroup mRoot;
+
public View mView;
private int mLayoutDirection;
@@ -8603,47 +8605,100 @@
return 1;
}
+ int boundsResult = compareBoundsOfTree(this, another);
+ if (boundsResult != 0) {
+ return boundsResult;
+ }
+
+ // Just break the tie somehow. The accessibility ids are unique
+ // and stable, hence this is deterministic tie breaking.
+ return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
+ }
+
+ /**
+ * Compare two views based on their bounds. Use the bounds of their children to break ties.
+ *
+ * @param holder1 Holder of first view to compare
+ * @param holder2 Holder of second view to compare. Must have the same root at holder1.
+ * @return The compare result, with equality if no good comparison was found.
+ */
+ private static int compareBoundsOfTree(
+ ViewLocationHolder holder1, ViewLocationHolder holder2) {
if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
// First is above second.
- if (mLocation.bottom - another.mLocation.top <= 0) {
+ if (holder1.mLocation.bottom - holder2.mLocation.top <= 0) {
return -1;
}
// First is below second.
- if (mLocation.top - another.mLocation.bottom >= 0) {
+ if (holder1.mLocation.top - holder2.mLocation.bottom >= 0) {
return 1;
}
}
// We are ordering left-to-right, top-to-bottom.
- if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
- final int leftDifference = mLocation.left - another.mLocation.left;
+ if (holder1.mLayoutDirection == LAYOUT_DIRECTION_LTR) {
+ final int leftDifference = holder1.mLocation.left - holder2.mLocation.left;
if (leftDifference != 0) {
return leftDifference;
}
} else { // RTL
- final int rightDifference = mLocation.right - another.mLocation.right;
+ final int rightDifference = holder1.mLocation.right - holder2.mLocation.right;
if (rightDifference != 0) {
return -rightDifference;
}
}
// We are ordering left-to-right, top-to-bottom.
- final int topDifference = mLocation.top - another.mLocation.top;
+ final int topDifference = holder1.mLocation.top - holder2.mLocation.top;
if (topDifference != 0) {
return topDifference;
}
// Break tie by height.
- final int heightDiference = mLocation.height() - another.mLocation.height();
+ final int heightDiference = holder1.mLocation.height() - holder2.mLocation.height();
if (heightDiference != 0) {
return -heightDiference;
}
// Break tie by width.
- final int widthDiference = mLocation.width() - another.mLocation.width();
- if (widthDiference != 0) {
- return -widthDiference;
+ final int widthDifference = holder1.mLocation.width() - holder2.mLocation.width();
+ if (widthDifference != 0) {
+ return -widthDifference;
}
- // Just break the tie somehow. The accessibliity ids are unique
- // and stable, hence this is deterministic tie breaking.
- return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
+
+ // Find a child of each view with different screen bounds.
+ final Rect view1Bounds = new Rect();
+ final Rect view2Bounds = new Rect();
+ final Rect tempRect = new Rect();
+ holder1.mView.getBoundsOnScreen(view1Bounds, true);
+ holder2.mView.getBoundsOnScreen(view2Bounds, true);
+ final View child1 = holder1.mView.findViewByPredicateTraversal((view) -> {
+ view.getBoundsOnScreen(tempRect, true);
+ return !tempRect.equals(view1Bounds);
+ }, null);
+ final View child2 = holder2.mView.findViewByPredicateTraversal((view) -> {
+ view.getBoundsOnScreen(tempRect, true);
+ return !tempRect.equals(view2Bounds);
+ }, null);
+
+
+ // Compare the children recursively
+ if ((child1 != null) && (child2 != null)) {
+ final ViewLocationHolder childHolder1 =
+ ViewLocationHolder.obtain(holder1.mRoot, child1);
+ final ViewLocationHolder childHolder2 =
+ ViewLocationHolder.obtain(holder1.mRoot, child2);
+ return compareBoundsOfTree(childHolder1, childHolder2);
+ }
+
+ // If only one has a child, use that one
+ if (child1 != null) {
+ return 1;
+ }
+
+ if (child2 != null) {
+ return -1;
+ }
+
+ // Give up
+ return 0;
}
private void init(ViewGroup root, View view) {
@@ -8651,6 +8706,7 @@
view.getDrawingRect(viewLocation);
root.offsetDescendantRectToMyCoords(view, viewLocation);
mView = view;
+ mRoot = root;
mLayoutDirection = root.getLayoutDirection();
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4104728..7e6af49 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -53,6 +53,7 @@
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.autofill.AutofillManager;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.os.SomeArgs;
@@ -406,6 +407,17 @@
static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
+ private static boolean isAutofillUIShowing(View servedView) {
+ AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
+ return afm != null && afm.isAutofillUiShowing();
+ }
+
+ private static boolean canStartInput(View servedView) {
+ // We can start input ether the servedView has window focus
+ // or the activity is showing autofill ui.
+ return servedView.hasWindowFocus() || isAutofillUIShowing(servedView);
+ }
+
class H extends Handler {
H(Looper looper) {
super(looper, null, true);
@@ -506,7 +518,7 @@
}
// Check focus again in case that "onWindowFocus" is called before
// handling this message.
- if (mServedView != null && mServedView.hasWindowFocus()) {
+ if (mServedView != null && canStartInput(mServedView)) {
if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) {
final int reason = active ?
InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
@@ -1435,7 +1447,7 @@
// at times when we don't really want it to. For now it
// seems better to just turn it all off.
// TODO: Check view.isTemporarilyDetached() when re-enable the following code.
- if (false && view.hasWindowFocus()) {
+ if (false && canStartInput(view)) {
mNextServedView = null;
scheduleCheckFocusLocked(view);
}
@@ -2572,6 +2584,7 @@
sb.append(view);
sb.append(",focus=" + view.hasFocus());
sb.append(",windowFocus=" + view.hasWindowFocus());
+ sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
sb.append(",window=" + view.getWindowToken());
sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
return sb.toString();
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 25af355..f42a195 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -16,10 +16,12 @@
package com.android.internal.app;
+import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Slog;
@@ -30,35 +32,47 @@
public class SuspendedAppActivity extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "SuspendedAppActivity";
-
public static final String EXTRA_SUSPENDED_PACKAGE =
"SuspendedAppActivity.extra.SUSPENDED_PACKAGE";
public static final String EXTRA_SUSPENDING_PACKAGE =
"SuspendedAppActivity.extra.SUSPENDING_PACKAGE";
public static final String EXTRA_DIALOG_MESSAGE = "SuspendedAppActivity.extra.DIALOG_MESSAGE";
- public static final String EXTRA_MORE_DETAILS_INTENT =
- "SuspendedAppActivity.extra.MORE_DETAILS_INTENT";
private Intent mMoreDetailsIntent;
private int mUserId;
+ private PackageManager mPm;
private CharSequence getAppLabel(String packageName) {
- final PackageManager pm = getPackageManager();
try {
- return pm.getApplicationInfoAsUser(packageName, 0, mUserId).loadLabel(pm);
+ return mPm.getApplicationInfoAsUser(packageName, 0, mUserId).loadLabel(mPm);
} catch (PackageManager.NameNotFoundException ne) {
Slog.e(TAG, "Package " + packageName + " not found", ne);
}
return packageName;
}
+ private Intent getMoreDetailsActivity(String suspendingPackage, String suspendedPackage,
+ int userId) {
+ final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
+ .setPackage(suspendingPackage);
+ final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
+ final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent, 0, userId);
+ if (resolvedInfo != null && resolvedInfo.activityInfo != null
+ && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
+ moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return moreDetailsIntent;
+ }
+ return null;
+ }
+
@Override
public void onCreate(Bundle icicle) {
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
super.onCreate(icicle);
+ mPm = getPackageManager();
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
final Intent intent = getIntent();
- mMoreDetailsIntent = intent.getParcelableExtra(EXTRA_MORE_DETAILS_INTENT);
mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
if (mUserId < 0) {
Slog.wtf(TAG, "Invalid user: " + mUserId);
@@ -66,13 +80,13 @@
return;
}
final String suppliedMessage = intent.getStringExtra(EXTRA_DIALOG_MESSAGE);
- final CharSequence suspendedAppLabel = getAppLabel(
- intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE));
+ final String suspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
+ final String suspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
+ final CharSequence suspendedAppLabel = getAppLabel(suspendedPackage);
final CharSequence dialogMessage;
if (suppliedMessage == null) {
- dialogMessage = getString(R.string.app_suspended_default_message,
- suspendedAppLabel,
- getAppLabel(intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE)));
+ dialogMessage = getString(R.string.app_suspended_default_message, suspendedAppLabel,
+ getAppLabel(suspendingPackage));
} else {
dialogMessage = String.format(getResources().getConfiguration().getLocales().get(0),
suppliedMessage, suspendedAppLabel);
@@ -82,6 +96,7 @@
ap.mTitle = getString(R.string.app_suspended_title);
ap.mMessage = dialogMessage;
ap.mPositiveButtonText = getString(android.R.string.ok);
+ mMoreDetailsIntent = getMoreDetailsActivity(suspendingPackage, suspendedPackage, mUserId);
if (mMoreDetailsIntent != null) {
ap.mNeutralButtonText = getString(R.string.app_suspended_more_details);
}
@@ -99,4 +114,16 @@
}
finish();
}
+
+ public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
+ String suspendingPackage, String dialogMessage, int userId) {
+ return new Intent()
+ .setClassName("android", SuspendedAppActivity.class.getName())
+ .putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
+ .putExtra(EXTRA_DIALOG_MESSAGE, dialogMessage)
+ .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
+ .putExtra(Intent.EXTRA_USER_ID, userId)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ }
}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index b2903c4..5563cce 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -218,8 +218,7 @@
}
/**
- * Reports whether {@link #getCarrierFrequencyHz(int satIndex)} is available (i.e. carrier
- * frequency is available for the satellite at the specified index).
+ * Reports whether a valid {@link #getCarrierFrequencyHz(int satIndex)} is available.
*
* @param satIndex the index of the satellite in the list.
*/
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 83d7e16..06fbf9f 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -811,6 +811,8 @@
List<ResolveInfo> resolvedActivities = getPackageManager()
.queryIntentActivities(intent, 0);
if (resolvedActivities.isEmpty()) {
+ Log.w(LOG_TAG, "Advanced options activity " + mAdvancedPrintOptionsActivity + " could "
+ + "not be found");
return;
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 299e337..680f14b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -38,7 +38,7 @@
public interface NotificationMenuRowPlugin extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
- public static final int VERSION = 3;
+ public static final int VERSION = 4;
@ProvidesInterface(version = OnMenuEventListener.VERSION)
public interface OnMenuEventListener {
@@ -75,6 +75,11 @@
*/
public MenuItem getAppOpsMenuItem(Context context);
+ /**
+ * @return the {@link MenuItem} to display when snooze item is pressed.
+ */
+ public MenuItem getSnoozeMenuItem(Context context);
+
public void setMenuItems(ArrayList<MenuItem> items);
public void setMenuClickListener(OnMenuEventListener listener);
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 458e133d7..99138b0 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -99,6 +99,7 @@
<item type="id" name="action_snooze_long"/>
<item type="id" name="action_snooze_longer"/>
<item type="id" name="action_snooze_assistant_suggestion_1"/>
+ <item type="id" name="action_snooze"/>
<!-- For StatusBarIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 939a868..2ff98ba 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -85,4 +85,9 @@
* cancel (long) press.
*/
void onQuickStep(in MotionEvent event);
+
+ /**
+ * Sent when there was an action on one of the onboarding tips view.
+ */
+ void onTip(int actionType, int viewType);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java
new file mode 100644
index 0000000..eed9580
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LauncherEventUtil.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+public class LauncherEventUtil {
+
+ // Constants for the Action
+ public static final int VISIBLE = 0;
+ public static final int DISMISS = 1;
+
+ // Constants for the Target (View)
+ public static final int RECENTS_SWIPE_UP_ONBOARDING_TIP = 0;
+ public static final int RECENTS_QUICK_SCRUB_ONBOARDING_TIP = 1;
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index d16e1b1..69b0f31 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -24,11 +24,18 @@
import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING;
import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT;
import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT;
+import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
+import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
import android.annotation.StringRes;
import android.annotation.TargetApi;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.CornerPathEffect;
@@ -38,6 +45,7 @@
import android.os.Build;
import android.os.SystemProperties;
import android.os.UserManager;
+import android.os.RemoteException;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -53,7 +61,9 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
+import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.LauncherEventUtil;
import java.util.Collections;
import java.util.HashSet;
@@ -120,6 +130,7 @@
return;
}
+ boolean shouldLog = false;
if (!alreadySeenSwipeUpOnboarding) {
if (getOpenedOverviewFromHomeCount()
>= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) {
@@ -128,10 +139,13 @@
if (mNumAppsLaunchedSinceSwipeUpTipDismiss
== SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS) {
mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
- show(R.string.recents_swipe_up_onboarding);
+ shouldLog = show(R.string.recents_swipe_up_onboarding);
}
} else {
- show(R.string.recents_swipe_up_onboarding);
+ shouldLog = show(R.string.recents_swipe_up_onboarding);
+ }
+ if (shouldLog) {
+ notifyOnTip(VISIBLE, RECENTS_SWIPE_UP_ONBOARDING_TIP);
}
}
} else {
@@ -140,12 +154,16 @@
if (mOverviewOpenedCountSinceQuickScrubTipDismiss
== QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
- show(R.string.recents_quick_scrub_onboarding);
+ shouldLog = show(R.string.recents_quick_scrub_onboarding);
}
} else {
- show(R.string.recents_quick_scrub_onboarding);
+ shouldLog = show(R.string.recents_quick_scrub_onboarding);
+ }
+ if (shouldLog) {
+ notifyOnTip(VISIBLE, RECENTS_QUICK_SCRUB_ONBOARDING_TIP);
}
}
+
}
} else {
hide(false);
@@ -191,6 +209,7 @@
@Override
public void onViewAttachedToWindow(View view) {
if (view == mLayout) {
+ mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
mLayoutAttachedToWindow = true;
if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) {
mHasDismissedSwipeUpTip = false;
@@ -215,6 +234,7 @@
}
mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
}
+ mContext.unregisterReceiver(mReceiver);
}
}
};
@@ -244,6 +264,9 @@
if (v.getTag().equals(R.string.recents_swipe_up_onboarding)) {
mHasDismissedSwipeUpTip = true;
mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
+ notifyOnTip(DISMISS, RECENTS_SWIPE_UP_ONBOARDING_TIP);
+ } else {
+ notifyOnTip(DISMISS, RECENTS_QUICK_SCRUB_ONBOARDING_TIP);
}
});
@@ -265,6 +288,15 @@
}
}
+ private void notifyOnTip(int action, int target) {
+ try {
+ IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+ if(overviewProxy != null) {
+ overviewProxy.onTip(action, target);
+ }
+ } catch (RemoteException e) {}
+ }
+
public void onConnectedToLauncher() {
if (!ONBOARDING_ENABLED) {
return;
@@ -307,9 +339,9 @@
}
}
- public void show(@StringRes int stringRes) {
+ public boolean show(@StringRes int stringRes) {
if (!shouldShow()) {
- return;
+ return false;
}
mDismissView.setTag(stringRes);
mLayout.setTag(stringRes);
@@ -328,7 +360,9 @@
.setDuration(SHOW_DURATION_MS)
.setInterpolator(new DecelerateInterpolator())
.start();
+ return true;
}
+ return false;
}
/**
@@ -370,7 +404,7 @@
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0, -mNavBarHeight / 2,
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
flags,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
@@ -427,4 +461,13 @@
private void setOpenedOverviewCount(int openedOverviewCount) {
Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount);
}
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+ hide(false);
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 82cf93e..b010199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -54,6 +54,7 @@
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.Chronometer;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -1599,6 +1600,10 @@
public void doLongClickCallback(int x, int y) {
createMenu();
MenuItem menuItem = getProvider().getLongpressMenuItem(mContext);
+ doLongClickCallback(x, y, menuItem);
+ }
+
+ private void doLongClickCallback(int x, int y, MenuItem menuItem) {
if (mLongPressListener != null && menuItem != null) {
mLongPressListener.onLongPress(this, x, y, menuItem);
}
@@ -2707,6 +2712,16 @@
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
}
}
+ NotificationMenuRowPlugin provider = getProvider();
+ if (provider != null) {
+ MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
+ if (snoozeMenu != null) {
+ AccessibilityAction action = new AccessibilityAction(R.id.action_snooze,
+ getContext().getResources()
+ .getString(R.string.notification_menu_snooze_action));
+ info.addAction(action);
+ }
+ }
}
@Override
@@ -2725,6 +2740,16 @@
case AccessibilityNodeInfo.ACTION_LONG_CLICK:
doLongClickCallback();
return true;
+ case R.id.action_snooze:
+ NotificationMenuRowPlugin provider = getProvider();
+ if (provider == null) {
+ provider = createMenu();
+ }
+ MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
+ if (snoozeMenu != null) {
+ doLongClickCallback(getWidth() / 2, getHeight() / 2, snoozeMenu);
+ }
+ return true;
}
return false;
}
@@ -2743,6 +2768,10 @@
return mNotificationViewState;
}
+ public NotificationViewState getViewState() {
+ return mNotificationViewState;
+ }
+
@Override
public boolean isAboveShelf() {
return !isOnKeyguard()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 8fa1b67..08d530b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -178,7 +178,7 @@
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
- int maxSize = Integer.MAX_VALUE;
+ int maxSize = Integer.MAX_VALUE / 2;
int width = MeasureSpec.getSize(widthMeasureSpec);
if (hasFixedHeight || isHeightLimited) {
maxSize = MeasureSpec.getSize(heightMeasureSpec);
@@ -189,17 +189,15 @@
if (mExpandedSmartReplyView != null) {
notificationMaxHeight += mExpandedSmartReplyView.getHeightUpperLimit();
}
- int size = Math.min(maxSize, notificationMaxHeight);
+ int size = notificationMaxHeight;
ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
boolean useExactly = false;
if (layoutParams.height >= 0) {
// An actual height is set
- size = Math.min(maxSize, layoutParams.height);
+ size = Math.min(size, layoutParams.height);
useExactly = true;
}
- int spec = size == Integer.MAX_VALUE
- ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- : MeasureSpec.makeMeasureSpec(size, useExactly
+ int spec = MeasureSpec.makeMeasureSpec(size, useExactly
? MeasureSpec.EXACTLY
: MeasureSpec.AT_MOST);
measureChildWithMargins(mExpandedChild, widthMeasureSpec, 0, spec, 0);
@@ -207,7 +205,7 @@
}
if (mContractedChild != null) {
int heightSpec;
- int size = Math.min(maxSize, mSmallHeight);
+ int size = mSmallHeight;
ViewGroup.LayoutParams layoutParams = mContractedChild.getLayoutParams();
boolean useExactly = false;
if (layoutParams.height >= 0) {
@@ -241,7 +239,7 @@
if (mHeadsUpChild != null) {
int maxHeight = mHeadsUpHeight;
maxHeight += mHeadsUpWrapper.getExtraMeasureHeight();
- int size = Math.min(maxSize, maxHeight);
+ int size = maxHeight;
ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
boolean useExactly = false;
if (layoutParams.height >= 0) {
@@ -263,11 +261,11 @@
MeasureSpec.EXACTLY);
}
mSingleLineView.measure(singleLineWidthSpec,
- MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
+ MeasureSpec.makeMeasureSpec(mNotificationMaxHeight, MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
}
if (mAmbientChild != null) {
- int size = Math.min(maxSize, mNotificationAmbientHeight);
+ int size = mNotificationAmbientHeight;
ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
boolean useExactly = false;
if (layoutParams.height >= 0) {
@@ -281,7 +279,7 @@
maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
}
if (mAmbientSingleLineChild != null) {
- int size = Math.min(maxSize, mNotificationAmbientHeight);
+ int size = mNotificationAmbientHeight;
ViewGroup.LayoutParams layoutParams = mAmbientSingleLineChild.getLayoutParams();
boolean useExactly = false;
if (layoutParams.height >= 0) {
@@ -1201,8 +1199,13 @@
}
private void updateSingleLineView() {
if (mIsChildInGroup) {
+ boolean isNewView = mSingleLineView == null;
mSingleLineView = mHybridGroupManager.bindFromNotification(
mSingleLineView, mStatusBarNotification.getNotification());
+ if (isNewView) {
+ updateViewVisibility(mVisibleType, VISIBLE_TYPE_SINGLELINE,
+ mSingleLineView, mSingleLineView);
+ }
} else if (mSingleLineView != null) {
removeView(mSingleLineView);
mSingleLineView = null;
@@ -1211,8 +1214,13 @@
private void updateAmbientSingleLineView() {
if (mIsChildInGroup) {
+ boolean isNewView = mAmbientSingleLineChild == null;
mAmbientSingleLineChild = mHybridGroupManager.bindAmbientFromNotification(
mAmbientSingleLineChild, mStatusBarNotification.getNotification());
+ if (isNewView) {
+ updateViewVisibility(mVisibleType, VISIBLE_TYPE_AMBIENT_SINGLELINE,
+ mAmbientSingleLineChild, mAmbientSingleLineChild);
+ }
} else if (mAmbientSingleLineChild != null) {
removeView(mAmbientSingleLineChild);
mAmbientSingleLineChild = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 7681530..f14ca71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -229,6 +229,7 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mMessagingUtil = new NotificationMessagingUtil(context);
mSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
+ mGroupManager.setPendingEntries(mPendingNotifications);
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -739,6 +740,7 @@
mNotificationData.getImportance(key));
mPendingNotifications.put(key, shadeEntry);
+ mGroupManager.onPendingEntryAdded(shadeEntry);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 0cc6137..eb46fba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -25,6 +25,7 @@
import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityEvent;
@@ -247,25 +248,29 @@
/** Animates in the guts view via either a fade or a circular reveal. */
private void animateOpen(
boolean shouldDoCircularReveal, int x, int y, @Nullable Runnable onAnimationEnd) {
- if (shouldDoCircularReveal) {
- double horz = Math.max(getWidth() - x, x);
- double vert = Math.max(getHeight() - y, y);
- float r = (float) Math.hypot(horz, vert);
- // Circular reveal originating at (x, y)
- Animator a = ViewAnimationUtils.createCircularReveal(this, x, y, 0, r);
- a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- a.addListener(new AnimateOpenListener(onAnimationEnd));
- a.start();
+ if (isAttachedToWindow()) {
+ if (shouldDoCircularReveal) {
+ double horz = Math.max(getWidth() - x, x);
+ double vert = Math.max(getHeight() - y, y);
+ float r = (float) Math.hypot(horz, vert);
+ // Circular reveal originating at (x, y)
+ Animator a = ViewAnimationUtils.createCircularReveal(this, x, y, 0, r);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ a.addListener(new AnimateOpenListener(onAnimationEnd));
+ a.start();
+ } else {
+ // Fade in content
+ this.setAlpha(0f);
+ this.animate()
+ .alpha(1f)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
+ .setInterpolator(Interpolators.ALPHA_IN)
+ .setListener(new AnimateOpenListener(onAnimationEnd))
+ .start();
+ }
} else {
- // Fade in content
- this.setAlpha(0f);
- this.animate()
- .alpha(1f)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
- .setInterpolator(Interpolators.ALPHA_IN)
- .setListener(new AnimateOpenListener(onAnimationEnd))
- .start();
+ Log.w(TAG, "Failed to animate guts open");
}
}
@@ -273,29 +278,33 @@
/** Animates out the guts view via either a fade or a circular reveal. */
@VisibleForTesting
void animateClose(int x, int y, boolean shouldDoCircularReveal) {
- if (shouldDoCircularReveal) {
- // Circular reveal originating at (x, y)
- if (x == -1 || y == -1) {
- x = (getLeft() + getRight()) / 2;
- y = (getTop() + getHeight() / 2);
+ if (isAttachedToWindow()) {
+ if (shouldDoCircularReveal) {
+ // Circular reveal originating at (x, y)
+ if (x == -1 || y == -1) {
+ x = (getLeft() + getRight()) / 2;
+ y = (getTop() + getHeight() / 2);
+ }
+ double horz = Math.max(getWidth() - x, x);
+ double vert = Math.max(getHeight() - y, y);
+ float r = (float) Math.hypot(horz, vert);
+ Animator a = ViewAnimationUtils.createCircularReveal(this,
+ x, y, r, 0);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ a.addListener(new AnimateCloseListener(this /* view */));
+ a.start();
+ } else {
+ // Fade in the blocking helper.
+ this.animate()
+ .alpha(0f)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .setListener(new AnimateCloseListener(this /* view */))
+ .start();
}
- double horz = Math.max(getWidth() - x, x);
- double vert = Math.max(getHeight() - y, y);
- float r = (float) Math.hypot(horz, vert);
- Animator a = ViewAnimationUtils.createCircularReveal(this,
- x, y, r, 0);
- a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- a.addListener(new AnimateCloseListener(this /* view */));
- a.start();
} else {
- // Fade in the blocking helper.
- this.animate()
- .alpha(0f)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
- .setInterpolator(Interpolators.ALPHA_OUT)
- .setListener(new AnimateCloseListener(this /* view */))
- .start();
+ Log.w(TAG, "Failed to animate guts close");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 0eb6bd4e..ada1a17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -70,6 +70,7 @@
private FrameLayout mMenuContainer;
private MenuItem mInfoItem;
private MenuItem mAppOpsItem;
+ private MenuItem mSnoozeItem;
private ArrayList<MenuItem> mMenuItems;
private OnMenuEventListener mMenuListener;
@@ -128,6 +129,11 @@
}
@Override
+ public MenuItem getSnoozeMenuItem(Context context) {
+ return mSnoozeItem;
+ }
+
+ @Override
public void setSwipeActionHelper(NotificationSwipeActionHelper helper) {
mSwipeHelper = helper;
}
@@ -190,7 +196,8 @@
boolean isForeground = (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
if (!isForeground) {
// Only show snooze for non-foreground notifications
- mMenuItems.add(createSnoozeItem(mContext));
+ mSnoozeItem = createSnoozeItem(mContext);
+ mMenuItems.add(mSnoozeItem);
}
}
mInfoItem = createInfoItem(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index c4a7814..76860e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -266,7 +266,9 @@
}
private void showBouncer() {
- mStatusBarKeyguardViewManager.showBouncer(false);
+ if (calculateMode() == MODE_SHOW_BOUNCER) {
+ mStatusBarKeyguardViewManager.showBouncer(false);
+ }
mStatusBarKeyguardViewManager.animateCollapsePanels(
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
mPendingShowBouncer = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 9ec5609..06f3c50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -36,7 +36,7 @@
/**
* Controls the appearance of heads up notifications in the icon area and the header itself.
*/
-class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
+public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
DarkIconDispatcher.DarkReceiver {
public static final int CONTENT_FADE_DURATION = 110;
public static final int CONTENT_FADE_DELAY = 100;
@@ -92,6 +92,7 @@
panelView.setHeadsUpAppearanceController(this);
mStackScroller.addOnExpandedHeightListener(mSetExpandedHeight);
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
+ mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mDarkIconDispatcher.addDarkReceiver(this);
@@ -226,10 +227,10 @@
});
}
- private void updateHeader(NotificationData.Entry entry) {
+ public void updateHeader(NotificationData.Entry entry) {
ExpandableNotificationRow row = entry.row;
float headerVisibleAmount = 1.0f;
- if (row.isPinned() || row == mTrackedChild) {
+ if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
headerVisibleAmount = mExpandFraction;
}
row.setHeaderVisibleAmount(headerVisibleAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index ca65965..55ffb3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import android.app.Notification;
+import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -29,9 +31,11 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
/**
* A class to handle notifications and their corresponding groups.
@@ -39,12 +43,14 @@
public class NotificationGroupManager implements OnHeadsUpChangedListener {
private static final String TAG = "NotificationGroupManager";
+ private static final long HEADS_UP_TRANSFER_TIMEOUT = 300;
private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
private OnGroupChangeListener mListener;
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
private HeadsUpManager mHeadsUpManager;
private boolean mIsUpdatingUnchangedGroup;
+ private HashMap<String, NotificationData.Entry> mPendingNotifications;
public void setOnGroupChangeListener(OnGroupChangeListener listener) {
mListener = listener;
@@ -147,6 +153,103 @@
mListener.onGroupCreatedFromChildren(group);
}
}
+ cleanUpHeadsUpStatesOnAdd(group, false /* addIsPending */);
+ }
+
+ public void onPendingEntryAdded(NotificationData.Entry shadeEntry) {
+ String groupKey = getGroupKey(shadeEntry.notification);
+ NotificationGroup group = mGroupMap.get(groupKey);
+ if (group != null) {
+ cleanUpHeadsUpStatesOnAdd(group, true /* addIsPending */);
+ }
+ }
+
+ /**
+ * Clean up the heads up states when a new child was added.
+ * @param group The group where a view was added or will be added.
+ * @param addIsPending True if is the addition still pending or false has it already been added.
+ */
+ private void cleanUpHeadsUpStatesOnAdd(NotificationGroup group, boolean addIsPending) {
+ if (!addIsPending && group.hunSummaryOnNextAddition) {
+ if (!mHeadsUpManager.isHeadsUp(group.summary.key)) {
+ mHeadsUpManager.showNotification(group.summary);
+ }
+ group.hunSummaryOnNextAddition = false;
+ }
+ // Because notification groups are not delivered as a whole unit, it may happen that a
+ // group child gets added quite a bit after the summary got posted. Our guidance is, that
+ // apps should always post the group summary as well and we'll hide it for them if the child
+ // is the only child in a group. Because of this, we also have to transfer heads up to the
+ // child, otherwise the invisible summary would be heads-upped.
+ // This transfer to the child is not always correct in case the app has just posted another
+ // child in addition to the existing one, but it hasn't arrived in systemUI yet. In such
+ // a scenario we would transfer the heads up to the old child and the wrong notification
+ // would be heads-upped. In oder to avoid this, we'll recover from this issue and hun the
+ // summary again instead of the old child if it's within a certain timeout.
+ if (SystemClock.elapsedRealtime() - group.lastHeadsUpTransfer < HEADS_UP_TRANSFER_TIMEOUT) {
+ if (!onlySummaryAlerts(group.summary)) {
+ return;
+ }
+ int numChildren = group.children.size();
+ NotificationData.Entry isolatedChild = getIsolatedChild(getGroupKey(
+ group.summary.notification));
+ int numPendingChildren = getPendingChildrenNotAlerting(group);
+ numChildren += numPendingChildren;
+ if (isolatedChild != null) {
+ numChildren++;
+ }
+ if (numChildren <= 1) {
+ return;
+ }
+ boolean releasedChild = false;
+ ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values());
+ int size = children.size();
+ for (int i = 0; i < size; i++) {
+ NotificationData.Entry entry = children.get(i);
+ if (onlySummaryAlerts(entry) && entry.row.isHeadsUp()) {
+ releasedChild = true;
+ mHeadsUpManager.releaseImmediately(entry.key);
+ }
+ }
+ if (isolatedChild != null && onlySummaryAlerts(isolatedChild)
+ && isolatedChild.row.isHeadsUp()) {
+ releasedChild = true;
+ mHeadsUpManager.releaseImmediately(isolatedChild.key);
+ }
+ if (releasedChild && !mHeadsUpManager.isHeadsUp(group.summary.key)) {
+ boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
+ if (notifyImmediately) {
+ mHeadsUpManager.showNotification(group.summary);
+ } else {
+ group.hunSummaryOnNextAddition = true;
+ }
+ group.lastHeadsUpTransfer = 0;
+ }
+ }
+ }
+
+ private int getPendingChildrenNotAlerting(NotificationGroup group) {
+ if (mPendingNotifications == null) {
+ return 0;
+ }
+ int number = 0;
+ String groupKey = getGroupKey(group.summary.notification);
+ Collection<NotificationData.Entry> values = mPendingNotifications.values();
+ for (NotificationData.Entry entry : values) {
+ if (!isGroupChild(entry.notification)) {
+ continue;
+ }
+ if (!Objects.equals(getGroupKey(entry.notification), groupKey)) {
+ continue;
+ }
+ if (group.children.containsKey(entry.key)) {
+ continue;
+ }
+ if (onlySummaryAlerts(entry)) {
+ number++;
+ }
+ }
+ return number;
}
private void onEntryBecomingChild(NotificationData.Entry entry) {
@@ -421,8 +524,16 @@
|| !entry.row.isHeadsUp()) {
return;
}
+
// The parent of a suppressed group got huned, lets hun the child!
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
+
+ if (pendingInflationsWillAddChildren(notificationGroup)) {
+ // New children will actually be added to this group, let's not transfer the heads
+ // up
+ return;
+ }
+
if (notificationGroup != null) {
Iterator<NotificationData.Entry> iterator
= notificationGroup.children.values().iterator();
@@ -438,6 +549,9 @@
if (mHeadsUpManager.isHeadsUp(child.key)) {
mHeadsUpManager.updateNotification(child, true);
} else {
+ if (onlySummaryAlerts(entry)) {
+ notificationGroup.lastHeadsUpTransfer = SystemClock.elapsedRealtime();
+ }
mHeadsUpManager.showNotification(child);
}
}
@@ -445,6 +559,35 @@
mHeadsUpManager.releaseImmediately(entry.key);
}
+ private boolean onlySummaryAlerts(NotificationData.Entry entry) {
+ return entry.notification.getNotification().getGroupAlertBehavior()
+ == Notification.GROUP_ALERT_SUMMARY;
+ }
+
+ /**
+ * Check if the pending inflations will add children to this group.
+ * @param group The group to check.
+ */
+ private boolean pendingInflationsWillAddChildren(NotificationGroup group) {
+ if (mPendingNotifications == null) {
+ return false;
+ }
+ Collection<NotificationData.Entry> values = mPendingNotifications.values();
+ String groupKey = getGroupKey(group.summary.notification);
+ for (NotificationData.Entry entry : values) {
+ if (!isGroupChild(entry.notification)) {
+ continue;
+ }
+ if (!Objects.equals(getGroupKey(entry.notification), groupKey)) {
+ continue;
+ }
+ if (!group.children.containsKey(entry.key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean shouldIsolate(StatusBarNotification sbn) {
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
return (sbn.isGroup() && !sbn.getNotification().isGroupSummary())
@@ -477,6 +620,10 @@
}
}
+ public void setPendingEntries(HashMap<String, NotificationData.Entry> pendingNotifications) {
+ mPendingNotifications = pendingNotifications;
+ }
+
public static class NotificationGroup {
public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
public NotificationData.Entry summary;
@@ -485,6 +632,12 @@
* Is this notification group suppressed, i.e its summary is hidden
*/
public boolean suppressed;
+ /**
+ * The time when the last heads transfer from group to child happened, while the summary
+ * has the flags to heads up on its own.
+ */
+ public long lastHeadsUpTransfer;
+ public boolean hunSummaryOnNextAddition;
@Override
public String toString() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 55ec142..45fa44c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -269,6 +269,12 @@
updateGroupOverflow();
row.setContentTransformationAmount(0, false /* isLastChild */);
+ // It doesn't make sense to keep old animations around, lets cancel them!
+ ExpandableNotificationRow.NotificationViewState viewState = row.getViewState();
+ if (viewState != null) {
+ viewState.cancelAnimations(row);
+ row.cancelAppearDrawing();
+ }
}
public void removeNotification(ExpandableNotificationRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 236ead0..ee70019 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -98,6 +98,7 @@
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -292,7 +293,7 @@
private int[] mTempInt2 = new int[2];
private boolean mGenerateChildOrderChangedEvent;
private HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
- private HashSet<View> mClearOverlayViewsWhenFinished = new HashSet<>();
+ private HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
= new HashSet<>();
private HeadsUpManagerPhone mHeadsUpManager;
@@ -413,6 +414,7 @@
private int mAntiBurnInOffsetX;
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
private int mHeadsUpInset;
+ private HeadsUpAppearanceController mHeadsUpAppearanceController;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -727,7 +729,7 @@
}
private void updateAlgorithmLayoutMinHeight() {
- mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() || isHeadsUpTransition()
+ mAmbientState.setLayoutMinHeight(mQsExpanded || isHeadsUpTransition()
? getLayoutMinHeight() : 0);
}
@@ -2451,7 +2453,6 @@
}
int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
int finalBottom = finalTranslationY + finalHeight - lastView.getClipBottomAmount();
- finalBottom = Math.min(finalBottom, getHeight());
if (mAnimateNextBackgroundBottom
|| mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
|| mBottomAnimator != null && mEndAnimationRect.bottom == finalBottom) {
@@ -2460,7 +2461,6 @@
} else {
bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
- lastView.getClipBottomAmount());
- bottom = Math.min(bottom, getHeight());
}
} else {
top = mTopPadding;
@@ -2473,7 +2473,7 @@
top = Math.max(0, top);
}
mBackgroundBounds.top = top;
- mBackgroundBounds.bottom = Math.min(getHeight(), Math.max(bottom, top));
+ mBackgroundBounds.bottom = Math.max(bottom, top);
}
private ActivatableNotificationView getFirstPinnedHeadsUp() {
@@ -2831,8 +2831,8 @@
return false;
}
if (isClickedHeadsUp(child)) {
- // An animation is already running, add it to the Overlay
- mClearOverlayViewsWhenFinished.add(child);
+ // An animation is already running, add it transiently
+ mClearTransientViewsWhenFinished.add((ExpandableView) child);
return true;
}
if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
@@ -3079,8 +3079,10 @@
@Override
public void bindRow(ExpandableNotificationRow row) {
- row.setHeadsUpAnimatingAwayListener(animatingAway
- -> mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway));
+ row.setHeadsUpAnimatingAwayListener(animatingAway -> {
+ mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway);
+ mHeadsUpAppearanceController.updateHeader(row.getEntry());
+ });
}
@Override
@@ -3202,6 +3204,7 @@
if (row.isChildInGroup()) {
// We can otherwise get stuck in there if it was just isolated
row.setHeadsUpAnimatingAway(false);
+ continue;
}
} else {
ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
@@ -3622,7 +3625,7 @@
}
private void clearTemporaryViews() {
- // lets make sure nothing is in the overlay / transient anymore
+ // lets make sure nothing is transient anymore
clearTemporaryViewsInGroup(this);
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
@@ -3637,9 +3640,6 @@
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
viewGroup.removeTransientView(viewGroup.getTransientView(0));
}
- if (viewGroup != null) {
- viewGroup.getOverlay().clear();
- }
}
public void onPanelTrackingStarted() {
@@ -3747,7 +3747,7 @@
setAnimationRunning(false);
requestChildrenUpdate();
runAnimationFinishedRunnables();
- clearViewOverlays();
+ clearTransient();
clearHeadsUpDisappearRunning();
}
@@ -3766,11 +3766,11 @@
}
}
- private void clearViewOverlays() {
- for (View view : mClearOverlayViewsWhenFinished) {
- StackStateAnimator.removeFromOverlay(view);
+ private void clearTransient() {
+ for (ExpandableView view : mClearTransientViewsWhenFinished) {
+ StackStateAnimator.removeTransientView(view);
}
- mClearOverlayViewsWhenFinished.clear();
+ mClearTransientViewsWhenFinished.clear();
}
private void runAnimationFinishedRunnables() {
@@ -4638,6 +4638,11 @@
mExpandedHeightListeners.remove(listener);
}
+ public void setHeadsUpAppearanceController(
+ HeadsUpAppearanceController headsUpAppearanceController) {
+ mHeadsUpAppearanceController = headsUpAppearanceController;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index f4d7f8d..85f33d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -478,6 +478,22 @@
childState.hidden = false;
}
}
+ // Let's hide all the views if we are not expanded. the views might otherwise be visible
+ // in the headsup area if a view was swiped away
+ if (!mIsExpanded) {
+ for (int i = 0; i < childCount; i++) {
+ boolean visible = false;
+ View child = algorithmState.visibleChildren.get(i);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ visible = row.isHeadsUp() || row.isHeadsUpAnimatingAway();
+ }
+ if (!visible) {
+ ExpandableViewState childState = resultState.getViewStateForView(child);
+ childState.hidden = true;
+ }
+ }
+ }
}
private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index d01db14..4e8fcac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -419,9 +419,6 @@
}, null);
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
- // A race condition can trigger the view to be added to the overlay even though
- // it was fully swiped out. So let's remove it
- mHostLayout.getOverlay().remove(changingView);
if (Math.abs(changingView.getTranslation()) == changingView.getWidth()
&& changingView.getTransientContainer() != null) {
changingView.getTransientContainer().removeTransientView(changingView);
@@ -469,8 +466,9 @@
? ANIMATION_DELAY_HEADS_UP_CLICKED
: 0;
if (changingView.getParent() == null) {
- // This notification was actually removed, so we need to add it to the overlay
- mHostLayout.getOverlay().add(changingView);
+ // This notification was actually removed, so we need to add it transiently
+ mHostLayout.addTransientView(changingView, 0);
+ changingView.setTransientContainer(mHostLayout);
mTmpState.initFrom(changingView);
mTmpState.yTranslation = 0;
// We temporarily enable Y animations, the real filter will be combined
@@ -479,10 +477,7 @@
mAnimationProperties.delay = extraDelay + ANIMATION_DELAY_HEADS_UP;
mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
mTmpState.animateTo(changingView, mAnimationProperties);
- endRunnable = () -> {
- // remove the temporary overlay
- removeFromOverlay(changingView);
- };
+ endRunnable = () -> removeTransientView(changingView);
}
float targetLocation = 0;
boolean needsAnimation = true;
@@ -517,19 +512,12 @@
}
}
- private static void removeTransientView(ExpandableView viewToRemove) {
+ public static void removeTransientView(ExpandableView viewToRemove) {
if (viewToRemove.getTransientContainer() != null) {
viewToRemove.getTransientContainer().removeTransientView(viewToRemove);
}
}
- public static void removeFromOverlay(View changingView) {
- ViewGroup parent = (ViewGroup) changingView.getParent();
- if (parent != null) {
- parent.removeView(changingView);
- }
- }
-
public void animateOverScrollToAmount(float targetAmount, final boolean onTop,
final boolean isRubberbanded) {
final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 611d4eb..1bdb7ad 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -54,6 +54,7 @@
// shouldn't be reset with tuner settings.
private static final String[] RESET_BLACKLIST = new String[] {
QSTileHost.TILES_SETTING,
+ Settings.Secure.DOZE_ALWAYS_ON
};
private final Observer mObserver = new Observer();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index a97effd..b360edc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -17,6 +17,8 @@
package com.android.systemui.volume;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
+import static android.media.AudioManager.RINGER_MODE_SILENT;
+import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
@@ -581,11 +583,28 @@
mState.ringerModeInternal = rm;
Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
- if (mState.ringerModeInternal == RINGER_MODE_NORMAL) {
- playTouchFeedback();
+ provideFeedback(mState.ringerModeInternal);
+ return true;
+ }
+
+ private void provideFeedback(int newRingerMode) {
+ VibrationEffect effect = null;
+ switch (newRingerMode) {
+ case RINGER_MODE_NORMAL:
+ scheduleTouchFeedback();
+ playTouchFeedback();
+ break;
+ case RINGER_MODE_SILENT:
+ effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ break;
+ case RINGER_MODE_VIBRATE:
+ default:
+ effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
}
- return true;
+ if (effect != null) {
+ vibrate(effect);
+ }
}
private void onSetRingerModeW(int mode, boolean external) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 6b322c7..2cff00c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -446,32 +446,12 @@
}
Events.writeEvent(mContext, Events.EVENT_RINGER_TOGGLE, newRingerMode);
updateRingerH();
- provideTouchFeedbackH(newRingerMode);
mController.setRingerMode(newRingerMode, false);
maybeShowToastH(newRingerMode);
});
updateRingerH();
}
-
- private void provideTouchFeedbackH(int newRingerMode) {
- VibrationEffect effect = null;
- switch (newRingerMode) {
- case RINGER_MODE_NORMAL:
- mController.scheduleTouchFeedback();
- break;
- case RINGER_MODE_SILENT:
- effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
- break;
- case RINGER_MODE_VIBRATE:
- default:
- effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
- }
- if (effect != null) {
- mController.vibrate(effect);
- }
- }
-
private void maybeShowToastH(int newRingerMode) {
int seenToastCount = Prefs.getInt(mContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, 0);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 95dc3ab..c22dac8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -188,6 +188,23 @@
ACCESS_METHOD_LINKING = 3; // never logged, included for completeness
}
+ enum HardwareType {
+ HARDWARE_UNKNOWN = 0;
+ HARDWARE_MICROPHONE = 1;
+ HARDWARE_CODEC = 2;
+ HARDWARE_SPEAKER = 3;
+ HARDWARE_FINGERPRINT = 4;
+ }
+
+ enum HardwareFailureCode {
+ HARDWARE_FAILURE_UNKNOWN = 0;
+ HARDWARE_FAILURE_COMPLETE = 1;
+ HARDWARE_FAILURE_SPEAKER_HIGH_Z = 2;
+ HARDWARE_FAILURE_SPEAKER_SHORT = 3;
+ HARDWARE_FAILURE_FINGERPRINT_SENSOR_BROKEN = 4;
+ HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -5296,11 +5313,11 @@
// OS: P
FIELD_DURATION_MILLIS = 1304;
- // Battery level in uA (0 - ~3,000,000 depending on device) when the current "mode" started.
+ // Battery level in uAh (0 - ~3,000,000 depending on device) when the current "mode" started.
// OS: P
FIELD_START_BATTERY_UA = 1305;
- // Battery level in uA (0 - ~3,000,000 depending on device) when this event was created.
+ // Battery level in uAh (0 - ~3,000,000 depending on device) when this event was created.
// OS: P
FIELD_END_BATTERY_UA = 1306;
@@ -5329,7 +5346,6 @@
// OS: P
FIELD_QS_MODE = 1311;
-
// OPEN: Settings->Developer Options->Default USB
// CATEGORY: SETTINGS
// OS: P
@@ -5733,8 +5749,8 @@
// OS: P
FIELD_HIDDEN_API_SIGNATURE = 1394;
- // This value should never appear in log outputs - it is reserved for
- // internal platform metrics use.
+ // The number of items in the shade when this notification event was logged.
+ // OS: P
NOTIFICATION_SHADE_COUNT = 1395;
// ACTION: DND Settings > What to block
@@ -5852,6 +5868,107 @@
// 3 = Wireless
FIELD_PLUG_TYPE = 1421;
+ // ACTION: USB-C Connector connected.
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_USB_CONNECTOR_CONNECTED = 1422;
+
+ // ACTION: USB-C Connector disconnected.
+ // CATEGORY: OTHER
+ // OS: P
+ // uses FIELD_DURATION_MILLIS for connected duration
+ ACTION_USB_CONNECTOR_DISCONNECTED = 1423;
+
+ // ACTION: USB-C Audio device connected
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_USB_AUDIO_CONNECTED = 1424;
+
+ // FIELD: VIDPID of connected USB Audio device
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_USB_AUDIO_VIDPID = 1425;
+
+ // ACTION: USB-C Audio device disconnected
+ // CATEGORY: OTHER
+ // OS: P
+ // use FIELD_DURATION_MILLIS for time
+ ACTION_USB_AUDIO_DISCONNECTED = 1426;
+
+ // ACTION: Hardware failure event
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_HARDWARE_FAILED = 1427;
+
+ // FIELD: Hardware failure category
+ // CATEGORY: OTHER
+ // OS: P
+ // Uses enum HardwareType
+ FIELD_HARDWARE_TYPE = 1428;
+
+ // FIELD: Hardware failure category
+ // CATEGORY: OTHER
+ // OS: P
+ // Uses enum HardwareFailureCode
+ FIELD_HARDWARE_FAILURE_CODE = 1429;
+
+ // ACTION: Physical drop event
+ // CATEGORY: OTHER
+ // OS: P
+ // use FIELD_DURATION_MILLIS for time
+ ACTION_PHYSICAL_DROP = 1430;
+
+ // FIELD: Confidence in detection of drop, in integer percentage.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_CONFIDENCE_PERCENT = 1431;
+
+ // FIELD: Detected bounce acceleration, in 1/1000th of a G.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_ACCEL_MILLI_G = 1432;
+
+ // ACTION: Battery health snapshot
+ // CATEGORY: OTHER
+ // OS: P
+ // uses FIELD_END_BATTERY_PERCENT for batt %
+ // uses FIELD_END_BATTERY_UA for instantaneous current load
+ ACTION_BATTERY_HEALTH = 1433;
+
+ // FIELD: Battery health snapshot type - min daily voltage, resistance, etc.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434;
+
+ // FIELD: Battery temperature at snapshop.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_TEMPERATURE = 1435;
+
+ // FIELD: Battery voltage at snapshot.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_VOLTAGE = 1436;
+
+ // FIELD: Battery open circuit voltage at snapshot.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE = 1437;
+
+ // ACTION: Battery charge cycles
+ // Number of times the battery has charged beyond a
+ // fractional threshold of full capacity.
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_BATTERY_CHARGE_CYCLES = 1438;
+
+ // FIELD: Battery charge cycles
+ // Number of times the battery has charged beyond a
+ // fractional threshold of full capacity.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_CHARGE_CYCLES = 1439;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index f9af31c..a9a14ca 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -184,19 +184,19 @@
NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED = 41;
// Inform the user that a wrong password was detected while attempting to connect
- // to a Wi-Fi network
+ // to a wifi network
NOTE_WIFI_WRONG_PASSWORD = 42;
// Inform the user that Wifi Wake will re-enable wifi when possible
NOTE_WIFI_WAKE_ONBOARD = 43;
- // Inform the user that Wifi Wake has automatically re-enabled Wifi
+ // Inform the user that Wifi Wake has automatically re-enabled wifi
NOTE_WIFI_WAKE_TURNED_BACK_ON = 44;
// Inform the user that unexpectedly rapid network usage is happening
NOTE_NET_RAPID = 45;
- // Notify the user that carrier Wi-Fi networks are available.
+ // Notify the user that carrier wifi networks are available.
// Package: android
NOTE_CARRIER_NETWORK_AVAILABLE = 46;
@@ -248,10 +248,10 @@
// Package: com.android.systemui
NOTE_TV_PIP = 1100;
- // Extreme battery saver notifiaction.
+ // Extreme battery saver notification.
NOTE_BATTERY_SAVER_WARNING = 1200;
- // Notify the user that open Wi-Fi networks are available.
+ // Notify the user that open wifi networks are available.
// Package: android
NOTE_NETWORK_AVAILABLE = 17303299;
@@ -261,7 +261,6 @@
// Notify the user about public volume state changes..
// Package: com.android.systemui
-
NOTE_STORAGE_PUBLIC = 0x53505542; // 1397773634
// Notify the user about private volume state changes.
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f992049..db8ad12 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -20,6 +20,8 @@
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -50,6 +52,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -96,13 +99,13 @@
import android.widget.RemoteViews;
import com.android.internal.R;
+import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsFactory;
@@ -110,7 +113,6 @@
import com.android.server.WidgetBackupProvider;
import com.android.server.policy.IconUtilities;
-import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -228,6 +230,7 @@
private AppOpsManager mAppOpsManager;
private KeyguardManager mKeyguardManager;
private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
+ private PackageManagerInternal mPackageManagerInternal;
private SecurityPolicy mSecurityPolicy;
@@ -254,6 +257,7 @@
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mSaveStateHandler = BackgroundThread.getHandler();
mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
mBackupRestoreController = new BackupRestoreController();
@@ -620,8 +624,17 @@
if (provider.maskedBySuspendedPackage) {
UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
showBadge = userInfo.isManagedProfile();
- onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
- providerUserId, true);
+ final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
+ providerPackage, providerUserId);
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
+ providerUserId, true);
+ } else {
+ final String dialogMessage = mPackageManagerInternal.getSuspendedDialogMessage(
+ providerPackage, providerUserId);
+ onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
+ providerPackage, suspendingPackage, dialogMessage, providerUserId);
+ }
} else if (provider.maskedByQuietProfile) {
showBadge = true;
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
@@ -824,6 +837,12 @@
mSecurityPolicy.enforceCallFromPackage(callingPackage);
synchronized (mLock) {
+ // Instant apps cannot host app widgets.
+ if (mSecurityPolicy.isInstantAppLocked(callingPackage, userId)) {
+ Slog.w(TAG, "Instant package " + callingPackage + " cannot host app widgets");
+ return ParceledListSlice.emptyList();
+ }
+
ensureGroupStateLoadedLocked(userId);
// NOTE: The lookup is enforcing security across users by making
@@ -890,6 +909,12 @@
mSecurityPolicy.enforceCallFromPackage(callingPackage);
synchronized (mLock) {
+ // Instant apps cannot host app widgets.
+ if (mSecurityPolicy.isInstantAppLocked(callingPackage, userId)) {
+ Slog.w(TAG, "Instant package " + callingPackage + " cannot host app widgets");
+ return AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
+
ensureGroupStateLoadedLocked(userId);
if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
@@ -1621,6 +1646,13 @@
@Override
public boolean isRequestPinAppWidgetSupported() {
+ synchronized (mLock) {
+ if (mSecurityPolicy.isCallerInstantAppLocked()) {
+ Slog.w(TAG, "Instant uid " + Binder.getCallingUid()
+ + " query information about app widgets");
+ return false;
+ }
+ }
return LocalServices.getService(ShortcutServiceInternal.class)
.isRequestPinItemSupported(UserHandle.getCallingUserId(),
LauncherApps.PinItemRequest.REQUEST_TYPE_APPWIDGET);
@@ -1671,6 +1703,12 @@
}
synchronized (mLock) {
+ if (mSecurityPolicy.isCallerInstantAppLocked()) {
+ Slog.w(TAG, "Instant uid " + Binder.getCallingUid()
+ + " cannot access widget providers");
+ return ParceledListSlice.emptyList();
+ }
+
ensureGroupStateLoadedLocked(userId);
ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>();
@@ -3652,6 +3690,35 @@
"hasBindAppWidgetPermission packageName=" + packageName);
}
+ public boolean isCallerInstantAppLocked() {
+ final int callingUid = Binder.getCallingUid();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final String[] uidPackages = mPackageManager.getPackagesForUid(callingUid);
+ if (!ArrayUtils.isEmpty(uidPackages)) {
+ return mPackageManager.isInstantApp(uidPackages[0],
+ UserHandle.getCallingUserId());
+ }
+ } catch (RemoteException e) {
+ /* ignore - same process */
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return false;
+ }
+
+ public boolean isInstantAppLocked(String packageName, int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mPackageManager.isInstantApp(packageName, userId);
+ } catch (RemoteException e) {
+ /* ignore - same process */
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return false;
+ }
+
public void enforceCallFromPackage(String packageName) {
mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 9b833f7..21398e3 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -588,7 +588,7 @@
private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
, int userId) {
- mAutofillCompatState.reset();
+ mAutofillCompatState.reset(userId);
final ArrayMap<String, Long> compatPackages =
service.getCompatibilityPackagesLocked();
if (compatPackages == null || compatPackages.isEmpty()) {
@@ -721,6 +721,9 @@
static final class AutofillCompatState {
private final Object mLock = new Object();
+ /**
+ * Map of app->compat_state per user.
+ */
@GuardedBy("mLock")
private SparseArray<ArrayMap<String, PackageCompatState>> mUserSpecs;
@@ -787,11 +790,17 @@
}
}
- void reset() {
+ void reset(int userId) {
synchronized (mLock) {
if (mUserSpecs != null) {
- mUserSpecs.clear();
- mUserSpecs = null;
+ mUserSpecs.delete(userId);
+ final int newSize = mUserSpecs.size();
+ if (newSize == 0) {
+ if (sVerbose) Slog.v(TAG, "reseting mUserSpecs");
+ mUserSpecs = null;
+ } else {
+ if (sVerbose) Slog.v(TAG, "mUserSpecs down to " + newSize);
+ }
}
}
}
@@ -806,7 +815,7 @@
for (int i = 0; i < mUserSpecs.size(); i++) {
final int user = mUserSpecs.keyAt(i);
pw.print(prefix); pw.print("User: "); pw.println(user);
- final ArrayMap<String,PackageCompatState> perUser = mUserSpecs.get(i);
+ final ArrayMap<String, PackageCompatState> perUser = mUserSpecs.valueAt(i);
for (int j = 0; j < perUser.size(); j++) {
final String packageName = perUser.keyAt(j);
final PackageCompatState state = perUser.valueAt(j);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 169f2a8..4c914c2 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -21,6 +21,7 @@
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -172,6 +173,9 @@
final AtomicFile mFile;
final Handler mHandler;
+ private final AppOpsManagerInternalImpl mAppOpsManagerInternal
+ = new AppOpsManagerInternalImpl();
+
boolean mWriteScheduled;
boolean mFastWriteScheduled;
final Runnable mWriteRunner = new Runnable() {
@@ -200,6 +204,8 @@
*/
private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
+ SparseIntArray mProfileOwners;
+
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
@@ -551,6 +557,7 @@
public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
+ LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
}
public void systemReady() {
@@ -921,12 +928,27 @@
}
}
+ void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
+ if (callingPid == Process.myPid()) {
+ return;
+ }
+ final int callingUser = UserHandle.getUserId(callingUid);
+ synchronized (this) {
+ if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
+ if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
+ // Profile owners are allowed to change modes but only for apps
+ // within their user.
+ return;
+ }
+ }
+ }
+ mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+
@Override
public void setUidMode(int code, int uid, int mode) {
- if (Binder.getCallingPid() != Process.myPid()) {
- mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
- }
+ enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
code = AppOpsManager.opToSwitch(code);
@@ -1029,10 +1051,7 @@
@Override
public void setMode(int code, int uid, String packageName, int mode) {
- if (Binder.getCallingPid() != Process.myPid()) {
- mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
- }
+ enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -1151,8 +1170,6 @@
public void resetAllModes(int reqUserId, String reqPackageName) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
- callingPid, callingUid, null);
reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
true, true, "resetAllModes", null);
@@ -1166,6 +1183,8 @@
}
}
+ enforceManageAppOpsModes(callingPid, callingUid, reqUid);
+
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
synchronized (this) {
boolean changed = false;
@@ -1428,10 +1447,9 @@
@Override
public void setAudioRestriction(int code, int usage, int uid, int mode,
String[] exceptionPackages) {
+ enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingUid(uid);
verifyIncomingOp(code);
- mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
synchronized (this) {
SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
if (usageRestrictions == null) {
@@ -2809,9 +2827,8 @@
return 0;
}
case "write-settings": {
- shell.mInternal.mContext.enforcePermission(
- android.Manifest.permission.MANAGE_APP_OPS_MODES,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
+ shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
+ Binder.getCallingUid(), -1);
long token = Binder.clearCallingIdentity();
try {
synchronized (shell.mInternal) {
@@ -2825,9 +2842,8 @@
return 0;
}
case "read-settings": {
- shell.mInternal.mContext.enforcePermission(
- android.Manifest.permission.MANAGE_APP_OPS_MODES,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
+ shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
+ Binder.getCallingUid(), -1);
long token = Binder.clearCallingIdentity();
try {
shell.mInternal.readState();
@@ -2989,6 +3005,17 @@
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final Date date = new Date();
boolean needSep = false;
+ if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
+ pw.println(" Profile owners:");
+ for (int poi = 0; poi < mProfileOwners.size(); poi++) {
+ pw.print(" User #");
+ pw.print(mProfileOwners.keyAt(poi));
+ pw.print(": ");
+ UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
+ pw.println();
+ }
+ pw.println();
+ }
if (mOpModeWatchers.size() > 0) {
boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
@@ -3702,4 +3729,12 @@
return true;
}
}
+
+ private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
+ @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
+ synchronized (AppOpsService.this) {
+ mProfileOwners = owners;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 27eae57..698b6f7 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -800,6 +800,20 @@
}
}
+ /**
+ * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ */
+ public void deferUpdateImeTarget() {
+ mWindowContainerController.deferUpdateImeTarget();
+ }
+
+ /**
+ * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ */
+ public void continueUpdateImeTarget() {
+ mWindowContainerController.continueUpdateImeTarget();
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
final String myPrefix = prefix + " ";
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 87d3696..c182502 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4595,46 +4595,58 @@
}
}
- // Shift all activities with this task up to the top
- // of the stack, keeping them in the same internal order.
- insertTaskAtTop(tr, null);
+ try {
+ // Defer updating the IME target since the new IME target will try to get computed
+ // before updating all closing and opening apps, which can cause the ime target to
+ // get calculated incorrectly.
+ getDisplay().deferUpdateImeTarget();
- // Don't refocus if invisible to current user
- final ActivityRecord top = tr.getTopActivity();
- if (top == null || !top.okToShowLocked()) {
- if (top != null) {
- mStackSupervisor.mRecentTasks.add(top.getTask());
+ // Shift all activities with this task up to the top
+ // of the stack, keeping them in the same internal order.
+ insertTaskAtTop(tr, null);
+
+ // Don't refocus if invisible to current user
+ final ActivityRecord top = tr.getTopActivity();
+ if (top == null || !top.okToShowLocked()) {
+ if (top != null) {
+ mStackSupervisor.mRecentTasks.add(top.getTask());
+ }
+ ActivityOptions.abort(options);
+ return;
}
- ActivityOptions.abort(options);
- return;
- }
- // Set focus to the top running activity of this stack.
- final ActivityRecord r = topRunningActivityLocked();
- mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason);
+ // Set focus to the top running activity of this stack.
+ final ActivityRecord r = topRunningActivityLocked();
+ mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason);
- if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
- if (noAnimation) {
- mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
- if (r != null) {
- mStackSupervisor.mNoAnimActivities.add(r);
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
+ if (noAnimation) {
+ mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ if (r != null) {
+ mStackSupervisor.mNoAnimActivities.add(r);
+ }
+ ActivityOptions.abort(options);
+ } else {
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
}
- ActivityOptions.abort(options);
- } else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
- }
- // If a new task is moved to the front, then mark the existing top activity as supporting
- // picture-in-picture while paused only if the task would not be considered an oerlay on top
- // of the current activity (eg. not fullscreen, or the assistant)
- if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,
- options)) {
- topActivity.supportsEnterPipOnTaskSwitch = true;
- }
+ // If a new task is moved to the front, then mark the existing top activity as
+ // supporting
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
+ // picture-in-picture while paused only if the task would not be considered an oerlay
+ // on top
+ // of the current activity (eg. not fullscreen, or the assistant)
+ if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,
+ options)) {
+ topActivity.supportsEnterPipOnTaskSwitch = true;
+ }
- mService.mTaskChangeNotificationController.notifyTaskMovedToFront(tr.taskId);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
+
+ mService.mTaskChangeNotificationController.notifyTaskMovedToFront(tr.taskId);
+ } finally {
+ getDisplay().continueUpdateImeTarget();
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 8c3ff34..ff97db8 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -34,7 +34,6 @@
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-import android.Manifest;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManagerInternal;
@@ -233,31 +232,6 @@
return true;
}
- private Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- String suspendingPackage, String dialogMessage, int userId) {
- final Intent interceptIntent = new Intent(mServiceContext, SuspendedAppActivity.class)
- .putExtra(SuspendedAppActivity.EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
- .putExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE, dialogMessage)
- .putExtra(SuspendedAppActivity.EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
- .putExtra(Intent.EXTRA_USER_ID, userId)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
- final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
- .setPackage(suspendingPackage);
- final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
- final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId,
- 0, mRealCallingUid);
- if (resolvedInfo != null && resolvedInfo.activityInfo != null
- && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
- moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- interceptIntent.putExtra(SuspendedAppActivity.EXTRA_MORE_DETAILS_INTENT,
- moreDetailsIntent);
- }
- return interceptIntent;
- }
-
private boolean interceptSuspendedPackageIfNeeded() {
// Do not intercept if the package is not suspended
if (mAInfo == null || mAInfo.applicationInfo == null ||
@@ -274,8 +248,8 @@
return interceptSuspendedByAdminPackage();
}
final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
- mIntent = createSuspendedAppInterceptIntent(suspendedPackage, suspendingPackage,
- dialogMessage, mUserId);
+ mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
+ suspendingPackage, dialogMessage, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 0425844..ce25a9f 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -330,7 +330,11 @@
}
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
- return mBrightnessMapper.setBrightnessConfiguration(configuration);
+ if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
+ resetShortTermModel();
+ return true;
+ }
+ return false;
}
public void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index f7439b9..5935829 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -341,7 +341,7 @@
// Extreme edge cases: use a simpler heuristic, as proper gamma correction around the edges
// affects the curve rather drastically.
if (currentBrightness <= 0.1f || currentBrightness >= 0.9f) {
- adjustment = (desiredBrightness - currentBrightness) * 2;
+ adjustment = (desiredBrightness - currentBrightness);
// Edge case: darkest adjustment possible.
} else if (desiredBrightness == 0) {
adjustment = -1;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c0dc750..f3423c6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -390,6 +390,11 @@
*/
int mLayoutSeq = 0;
+ /**
+ * Specifies the count to determine whether to defer updating the IME target until ready.
+ */
+ private int mDeferUpdateImeTargetCount;
+
/** Temporary float array to retrieve 3x3 matrix values. */
private final float[] mTmpFloats = new float[9];
@@ -2454,6 +2459,12 @@
return null;
}
+ final WindowState curTarget = mService.mInputMethodTarget;
+ if (!canUpdateImeTarget()) {
+ if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Defer updating IME target");
+ return curTarget;
+ }
+
// TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
// same display. Or even when the current IME/target are not on the same screen as the next
// IME/target. For now only look for input windows on the main screen.
@@ -2477,16 +2488,13 @@
if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.v(TAG_WM,
"Proposed new IME target: " + target);
- // Now, a special case -- if the last target's window is in the process of exiting, and is
- // above the new target, keep on the last target to avoid flicker. Consider for example a
- // Dialog with the IME shown: when the Dialog is dismissed, we want to keep the IME above it
- // until it is completely gone so it doesn't drop behind the dialog or its full-screen
- // scrim.
- final WindowState curTarget = mService.mInputMethodTarget;
+ // Now, a special case -- if the last target's window is in the process of exiting, and the
+ // new target is home, keep on the last target to avoid flicker. Home is a special case
+ // since its above other stacks in the ordering list, but layed out below the others.
if (curTarget != null && curTarget.isDisplayedLw() && curTarget.isClosing()
- && (target == null
- || curTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer)) {
- if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Current target higher, not changing");
+ && (target == null || target.isActivityTypeHome())) {
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "New target is home while current target is"
+ + "closing, not changing");
return curTarget;
}
@@ -3958,4 +3966,33 @@
void assignStackOrdering() {
mTaskStackContainers.assignStackOrdering(getPendingTransaction());
}
+
+ /**
+ * Increment the deferral count to determine whether to update the IME target.
+ */
+ void deferUpdateImeTarget() {
+ mDeferUpdateImeTargetCount++;
+ }
+
+ /**
+ * Decrement the deferral count to determine whether to update the IME target. If the count
+ * reaches 0, a new ime target will get computed.
+ */
+ void continueUpdateImeTarget() {
+ if (mDeferUpdateImeTargetCount == 0) {
+ return;
+ }
+
+ mDeferUpdateImeTargetCount--;
+ if (mDeferUpdateImeTargetCount == 0) {
+ computeImeTarget(true /* updateImeTarget */);
+ }
+ }
+
+ /**
+ * @return Whether a new IME target should be computed.
+ */
+ private boolean canUpdateImeTarget() {
+ return mDeferUpdateImeTargetCount == 0;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index ba8ec69..a1639c2 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -94,6 +94,31 @@
}
}
+ /**
+ * Starts deferring the ability to update the IME target. This is needed when a call will
+ * attempt to update the IME target before all information about the Windows have been updated.
+ */
+ public void deferUpdateImeTarget() {
+ synchronized (mWindowMap) {
+ final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
+ if (dc != null) {
+ dc.deferUpdateImeTarget();
+ }
+ }
+ }
+
+ /**
+ * Resumes updating the IME target after deferring. See {@link #deferUpdateImeTarget()}
+ */
+ public void continueUpdateImeTarget() {
+ synchronized (mWindowMap) {
+ final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
+ if (dc != null) {
+ dc.continueUpdateImeTarget();
+ }
+ }
+ }
+
@Override
public String toString() {
return "{DisplayWindowController displayId=" + mDisplayId + "}";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93d6ae8..16399008 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2697,12 +2697,7 @@
+ " Callers=" + Debug.getCallers(5));
if (mAppTransition.isTransitionSet()) {
mAppTransition.setReady();
- final long origId = Binder.clearCallingIdentity();
- try {
- mWindowPlacerLocked.performSurfacePlacement();
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
+ mWindowPlacerLocked.requestTraversal();
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c710c97..91c449b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2726,7 +2726,8 @@
}
boolean isClosing() {
- return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
+ return mAnimatingExit || (mAppToken != null && mAppToken.isAnimating()
+ && mAppToken.hiddenRequested);
}
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 729dba5..c370a00 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3351,6 +3351,7 @@
case SystemService.PHASE_LOCK_SETTINGS_READY:
onLockSettingsReady();
loadAdminDataAsync();
+ mOwners.systemReady();
break;
case SystemService.PHASE_BOOT_COMPLETED:
ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 8366114..632f0aa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -17,11 +17,14 @@
package com.android.server.devicepolicy;
import android.annotation.Nullable;
+import android.app.AppOpsManagerInternal;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
+import android.os.Binder;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
@@ -32,10 +35,12 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,6 +104,8 @@
private final UserManagerInternal mUserManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
+ private boolean mSystemReady;
+
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
@@ -179,6 +186,7 @@
getDeviceOwnerUserId()));
}
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -262,6 +270,7 @@
mUserManagerInternal.setDeviceManaged(true);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -272,6 +281,7 @@
mUserManagerInternal.setDeviceManaged(false);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -283,6 +293,7 @@
/* remoteBugreportHash =*/ null));
mUserManagerInternal.setUserManaged(userId, true);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -291,6 +302,7 @@
mProfileOwners.remove(userId);
mUserManagerInternal.setUserManaged(userId, false);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -302,6 +314,7 @@
ownerInfo.remoteBugreportHash);
mProfileOwners.put(userId, newOwnerInfo);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -313,6 +326,7 @@
mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
mDeviceOwner.remoteBugreportHash);
pushToPackageManagerLocked();
+ pushToAppOpsLocked();
}
}
@@ -581,6 +595,48 @@
}
}
+ void pushToAppOpsLocked() {
+ if (!mSystemReady) {
+ return;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final SparseIntArray owners = new SparseIntArray();
+ if (mDeviceOwner != null) {
+ final int uid = mPackageManagerInternal.getPackageUid(mDeviceOwner.packageName,
+ PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
+ mDeviceOwnerUserId);
+ if (uid >= 0) {
+ owners.put(mDeviceOwnerUserId, uid);
+ }
+ }
+ if (mProfileOwners != null) {
+ for (int poi = mProfileOwners.size() - 1; poi >= 0; poi--) {
+ final int uid = mPackageManagerInternal.getPackageUid(
+ mProfileOwners.valueAt(poi).packageName,
+ PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
+ mProfileOwners.keyAt(poi));
+ if (uid >= 0) {
+ owners.put(mProfileOwners.keyAt(poi), uid);
+ }
+ }
+ }
+ AppOpsManagerInternal appops = LocalServices.getService(AppOpsManagerInternal.class);
+ if (appops != null) {
+ appops.setDeviceAndProfileOwners(owners.size() > 0 ? owners : null);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void systemReady() {
+ synchronized (mLock) {
+ mSystemReady = true;
+ pushToAppOpsLocked();
+ }
+ }
+
private abstract static class FileReadWriter {
private final File mFile;
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 83a125d..dc55179b 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -18,8 +18,12 @@
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_INSTANT;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.ComponentName;
@@ -36,6 +40,8 @@
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.print.IPrintDocumentAdapter;
@@ -122,6 +128,13 @@
}
@Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ new PrintShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
adapter = Preconditions.checkNotNull(adapter);
@@ -717,6 +730,46 @@
}
}
+ @Override
+ public boolean getBindInstantServiceAllowed(@UserIdInt int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != SHELL_UID && callingUid != ROOT_UID) {
+ throw new SecurityException("Can only be called by uid " + SHELL_UID
+ + " or " + ROOT_UID);
+ }
+
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(userId, false);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getBindInstantServiceAllowed();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void setBindInstantServiceAllowed(@UserIdInt int userId, boolean allowed) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != SHELL_UID && callingUid != ROOT_UID) {
+ throw new SecurityException("Can only be called by uid " + SHELL_UID
+ + " or " + ROOT_UID);
+ }
+
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(userId, false);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ userState.setBindInstantServiceAllowed(allowed);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private boolean isPrintingEnabled() {
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING,
Binder.getCallingUserHandle());
@@ -773,7 +826,7 @@
List<ResolveInfo> installedServices = mContext.getPackageManager()
.queryIntentServicesAsUser(intent,
- GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
+ GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING | MATCH_INSTANT,
getChangingUserId());
return installedServices != null && !installedServices.isEmpty();
@@ -988,7 +1041,7 @@
return appId;
}
final int callingAppId = UserHandle.getAppId(callingUid);
- if (appId == callingAppId || callingAppId == Process.SHELL_UID
+ if (appId == callingAppId || callingAppId == SHELL_UID
|| callingAppId == Process.SYSTEM_UID) {
return appId;
}
diff --git a/services/print/java/com/android/server/print/PrintShellCommand.java b/services/print/java/com/android/server/print/PrintShellCommand.java
new file mode 100644
index 0000000..11642e5
--- /dev/null
+++ b/services/print/java/com/android/server/print/PrintShellCommand.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.print;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.print.IPrintManager;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell command implementation for the print manager service
+ */
+final class PrintShellCommand extends ShellCommand {
+ final @NonNull IPrintManager mService;
+
+ PrintShellCommand(@NonNull IPrintManager service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(@Nullable String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "get-bind-instant-service-allowed": {
+ return runGetBindInstantServiceAllowed();
+ }
+ case "set-bind-instant-service-allowed": {
+ return runSetBindInstantServiceAllowed();
+ }
+ }
+ return -1;
+ }
+
+ private int runGetBindInstantServiceAllowed() {
+ final Integer userId = parseUserId();
+ if (userId == null) {
+ return -1;
+ }
+ try {
+ getOutPrintWriter().println(
+ Boolean.toString(mService.getBindInstantServiceAllowed(userId)));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return 0;
+ }
+
+ private int runSetBindInstantServiceAllowed() {
+ final Integer userId = parseUserId();
+ if (userId == null) {
+ return -1;
+ }
+ final String allowed = getNextArgRequired();
+ if (allowed == null) {
+ getErrPrintWriter().println("Error: no true/false specified");
+ return -1;
+ }
+ try {
+ mService.setBindInstantServiceAllowed(userId, Boolean.parseBoolean(allowed));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return 0;
+ }
+
+ private @Nullable Integer parseUserId() {
+ final String option = getNextOption();
+ if (option != null) {
+ if (option.equals("--user")) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Unknown option: " + option);
+ return null;
+ }
+ }
+ return UserHandle.USER_SYSTEM;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Print service commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+ pw.println(" Set whether binding to print services provided by instant apps is "
+ + "allowed.");
+ pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]");
+ pw.println(" Get whether binding to print services provided by instant apps is "
+ + "allowed.");
+ }
+}
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index d4cbe7b..4f0d6f1 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -571,8 +571,8 @@
mBinding = true;
boolean wasBound = mContext.bindServiceAsUser(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(mUserId));
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_INSTANT, new UserHandle(mUserId));
if (!wasBound) {
if (DEBUG) {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 62185d7..4fbc14c 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_INSTANT;
import static com.android.internal.print.DumpUtils.writePrintJobInfo;
import static com.android.internal.print.DumpUtils.writePrinterId;
@@ -155,6 +156,11 @@
*/
private RemotePrintServiceRecommendationService mPrintServiceRecommendationsService;
+ /**
+ * Can services from instant apps be bound? (usually disabled, only used by testing)
+ */
+ private boolean mIsInstantServiceAllowed;
+
public UserState(Context context, int userId, Object lock, boolean lowPriority) {
mContext = context;
mUserId = userId;
@@ -872,9 +878,14 @@
private void readInstalledPrintServicesLocked() {
Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
+ int queryIntentFlags = GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING;
+
+ if (mIsInstantServiceAllowed) {
+ queryIntentFlags |= MATCH_INSTANT;
+ }
+
List<ResolveInfo> installedServices = mContext.getPackageManager()
- .queryIntentServicesAsUser(mQueryIntent,
- GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING, mUserId);
+ .queryIntentServicesAsUser(mQueryIntent, queryIntentFlags, mUserId);
final int installedCount = installedServices.size();
for (int i = 0, count = installedCount; i < count; i++) {
@@ -1185,6 +1196,18 @@
}
}
+ public boolean getBindInstantServiceAllowed() {
+ return mIsInstantServiceAllowed;
+ }
+
+ public void setBindInstantServiceAllowed(boolean allowed) {
+ synchronized (mLock) {
+ mIsInstantServiceAllowed = allowed;
+
+ updateIfNeededLocked();
+ }
+ }
+
private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
@NonNull final IPrintJobStateChangeListener listener;
final int appId;
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 4b827d2..e33ba7e 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
@@ -100,6 +101,7 @@
}
/** @hide */
+ @TestApi
public CallAudioState(boolean isMuted, @CallAudioRoute int route,
@CallAudioRoute int supportedRouteMask,
@Nullable BluetoothDevice activeBluetoothDevice,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5a77a9f..487490c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3443,14 +3443,13 @@
* to the TelephonyManager.
* When the filter is enabled, {@link
* VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be
- * called when a SMS matching the settings is received. The caller should have
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implement a
- * VisualVoicemailService.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * called when a SMS matching the settings is received. Caller must be the default dialer,
+ * system dialer, or carrier visual voicemail app.
*
* @param settings The settings for the filter, or {@code null} to disable the filter.
+ *
+ * @see {@link TelecomManager#getDefaultDialerPackage()}
+ * @see {@link CarrierConfigManager#KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}
*/
public void setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings settings) {
if (settings == null) {
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 4e202df..3689a8f 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -421,7 +421,7 @@
printf(" NULL),\n");
break;
case SECTION_DUMPSYS:
- printf(" new DumpsysSection(%d, \"%s\",", field->number(),
+ printf(" new DumpsysSection(%d, %s,", field->number(),
s.userdebug_and_eng_only() ? "true" : "false");
splitAndPrint(s.args());
printf(" NULL),\n");