Merge "Allow location provider to deep link into permissions UI"
diff --git a/Android.bp b/Android.bp
index 10b92f3..93e6963 100644
--- a/Android.bp
+++ b/Android.bp
@@ -766,6 +766,16 @@
],
}
+// A host library containing the inspector annotations for inspector-annotation-processor.
+java_library_host {
+ name: "inspector-annotation",
+ srcs: [
+ "core/java/android/view/inspector/InspectableChildren.java",
+ "core/java/android/view/inspector/InspectableNodeName.java",
+ "core/java/android/view/inspector/InspectableProperty.java",
+ ],
+}
+
// A host library including just UnsupportedAppUsage.java so that the annotation
// processor can also use this annotation.
java_library_host {
diff --git a/api/current.txt b/api/current.txt
index 673309d..a5724fe 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -769,6 +769,7 @@
field public static final int insetRight = 16843192; // 0x10101b8
field public static final int insetTop = 16843193; // 0x10101b9
field public static final int installLocation = 16843447; // 0x10102b7
+ field public static final int interactiveUiTimeout = 16844181; // 0x1010595
field public static final int interpolator = 16843073; // 0x1010141
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
field public static final int isAsciiCapable = 16843753; // 0x10103e9
@@ -941,7 +942,6 @@
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
- field public static final int minimumUiTimeout = 16844175; // 0x101058f
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
field public static final int mipMap = 16843725; // 0x10103cd
field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -965,6 +965,7 @@
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
field public static final int noHistory = 16843309; // 0x101022d
+ field public static final int nonInteractiveUiTimeout = 16844175; // 0x101058f
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
@@ -2886,12 +2887,14 @@
method public int getCapabilities();
method public deprecated java.lang.String getDescription();
method public java.lang.String getId();
- method public int getMinimumUiTimeoutMillis();
+ method public int getInteractiveUiTimeoutMillis();
+ method public int getNonInteractiveUiTimeoutMillis();
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
- method public void setMinimumUiTimeoutMillis(int);
+ method public void setInteractiveUiTimeoutMillis(int);
+ method public void setNonInteractiveUiTimeoutMillis(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
@@ -11176,12 +11179,17 @@
public static class PackageInstaller.Session implements java.io.Closeable {
method public void abandon();
+ method public void addChildSessionId(int);
method public void close();
method public void commit(android.content.IntentSender);
method public void fsync(java.io.OutputStream) throws java.io.IOException;
+ method public int[] getChildSessionIds();
method public java.lang.String[] getNames() throws java.io.IOException;
+ method public int getParentSessionId();
+ method public boolean isMultiPackage();
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+ method public void removeChildSessionId(int);
method public void removeSplit(java.lang.String) throws java.io.IOException;
method public void setStagingProgress(float);
method public void transfer(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11202,20 +11210,24 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int[] getChildSessionIds();
method public int getInstallLocation();
method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public int getMode();
method public int getOriginatingUid();
method public android.net.Uri getOriginatingUri();
+ method public int getParentSessionId();
method public float getProgress();
method public android.net.Uri getReferrerUri();
method public int getSessionId();
method public long getSize();
method public boolean isActive();
+ method public boolean isMultiPackage();
method public boolean isSealed();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
+ field public static final int INVALID_ID = -1; // 0xffffffff
}
public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -11226,6 +11238,7 @@
method public void setAppPackageName(java.lang.String);
method public void setInstallLocation(int);
method public void setInstallReason(int);
+ method public void setMultiPackage();
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -14980,7 +14993,7 @@
method public final int getLevel();
method public int getMinimumHeight();
method public int getMinimumWidth();
- method public abstract int getOpacity();
+ method public abstract deprecated int getOpacity();
method public android.graphics.Insets getOpticalInsets();
method public void getOutline(android.graphics.Outline);
method public boolean getPadding(android.graphics.Rect);
@@ -35681,6 +35694,15 @@
method public static java.lang.String getLastOutgoingCall(android.content.Context);
field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
field public static final int BLOCKED_TYPE = 6; // 0x6
+ field public static final java.lang.String BLOCK_REASON = "block_reason";
+ field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
+ field public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; // 0x1
+ field public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; // 0x2
+ field public static final int BLOCK_REASON_NOT_BLOCKED = 0; // 0x0
+ field public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7; // 0x7
+ field public static final int BLOCK_REASON_PAY_PHONE = 6; // 0x6
+ field public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; // 0x5
+ field public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; // 0x4
field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
@@ -35690,6 +35712,8 @@
field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
+ field public static final java.lang.String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+ field public static final java.lang.String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -40342,6 +40366,7 @@
public static class NotificationListenerService.Ranking {
ctor public NotificationListenerService.Ranking();
+ method public boolean audiblyAlerted();
method public boolean canShowBadge();
method public android.app.NotificationChannel getChannel();
method public int getImportance();
@@ -42874,6 +42899,16 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR;
}
+ public final class CellIdentityNr extends android.telephony.CellIdentity {
+ method public int getChannelNumber();
+ method public java.lang.String getMccString();
+ method public java.lang.String getMncString();
+ method public int getPci();
+ method public int getTac();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityNr> CREATOR;
+ }
+
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
method public int getCid();
method public int getCpid();
@@ -42933,6 +42968,13 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
}
+ public final class CellInfoNr extends android.telephony.CellInfo {
+ method public android.telephony.CellIdentity getCellIdentity();
+ method public android.telephony.CellSignalStrength getCellSignalStrength();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellInfoNr> CREATOR;
+ }
+
public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
method public android.telephony.CellIdentityWcdma getCellIdentity();
method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
@@ -42999,6 +43041,21 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthLte> CREATOR;
}
+ public final class CellSignalStrengthNr extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAsuLevel();
+ method public int getCsiRsrp();
+ method public int getCsiRsrq();
+ method public int getCsiSinr();
+ method public int getDbm();
+ method public int getLevel();
+ method public int getSsRsrp();
+ method public int getSsRsrq();
+ method public int getSsSinr();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthNr> CREATOR;
+ }
+
public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
method public int describeContents();
method public int getAsuLevel();
@@ -50464,7 +50521,7 @@
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
- method public int getMinimumUiTimeoutMillis();
+ method public int getRecommendedTimeoutMillis(int, int);
method public void interrupt();
method public static boolean isAccessibilityButtonSupported();
method public boolean isEnabled();
@@ -50473,6 +50530,9 @@
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+ field public static final int FLAG_CONTENT_CONTROLS = 4; // 0x4
+ field public static final int FLAG_CONTENT_ICONS = 1; // 0x1
+ field public static final int FLAG_CONTENT_TEXT = 2; // 0x2
}
public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6bb6d50..237d4c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3834,6 +3834,14 @@
}
+package android.net.wifi.p2p {
+
+ public class WifiP2pManager {
+ method public void factoryReset(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ }
+
+}
+
package android.net.wifi.rtt {
public static final class RangingRequest.Builder {
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index ff436f1..e5764f0 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -24213,7 +24213,90 @@
HSPLandroid/icu/util/CharsTrie;->next(I)Landroid/icu/util/BytesTrie$Result;
HSPLandroid/icu/util/CharsTrie;->nextImpl(II)Landroid/icu/util/BytesTrie$Result;
HSPLandroid/icu/util/CharsTrie;->readValue(Ljava/lang/CharSequence;II)I
-HSPLandroid/icu/util/Currency$1;-><init>()V
+HSPLandroid/icu/util/CodePointTrie$Small8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small8;
+HSPLandroid/icu/util/CodePointTrie$Small32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small32;
+HSPLandroid/icu/util/CodePointTrie$Small16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small16;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast8;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast32;
+HSPLandroid/icu/util/CodePointTrie$Fast32;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast16;
+HSPLandroid/icu/util/CodePointTrie$Fast16;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small;
+HSPLandroid/icu/util/CodePointTrie$Small;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Small;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast;
+HSPLandroid/icu/util/CodePointTrie$Fast;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Fast;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data8;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data32;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data16;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->values()[Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Type;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Type;->values()[Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->fromBinary(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/CodePointTrie;->internalSmallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/CodePointTrie;->asciiGet(I)I
+HSPLandroid/icu/util/CodePointTrie;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->fastIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->get(I)I
+HSPLandroid/icu/util/CodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointTrie;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie;->smallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->toBinary(Ljava/io/OutputStream;)I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getCodePoint()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getIndex()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getValue()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->next()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->previous()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->reset(Ljava/lang/CharSequence;I)V
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->hasNext()Z
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Landroid/icu/util/CodePointMap$Range;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Ljava/lang/Object;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->remove()V
+HSPLandroid/icu/util/CodePointMap$Range;->access$000(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$002(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$100(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$102(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$202(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->getEnd()I
+HSPLandroid/icu/util/CodePointMap$Range;->getStart()I
+HSPLandroid/icu/util/CodePointMap$Range;->getValue()I
+HSPLandroid/icu/util/CodePointMap$Range;->set(III)V
+HSPLandroid/icu/util/CodePointMap$ValueFilter;->apply(I)I
+HSPLandroid/icu/util/CodePointMap$RangeOption;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap$RangeOption;->values()[Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap;->get(I)I
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$RangeOption;ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->iterator()Ljava/util/Iterator;
+HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;HSPLandroid/icu/util/Currency$1;-><init>()V
HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/String;Ljava/lang/Void;)Landroid/icu/util/Currency;
HSPLandroid/icu/util/Currency$CurrencyUsage;-><init>(Ljava/lang/String;I)V
@@ -24259,6 +24342,61 @@
HSPLandroid/icu/util/MeasureUnit;->equals(Ljava/lang/Object;)Z
HSPLandroid/icu/util/MeasureUnit;->hashCode()I
HSPLandroid/icu/util/MeasureUnit;->internalGetInstance(Ljava/lang/String;Ljava/lang/String;)Landroid/icu/util/MeasureUnit;
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->addEntry([I[CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([III)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([I[C[I[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode(I)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->modulo(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->nextIndex(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findAllSameBlock([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([I[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->init(II)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->add(III)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findMostUsed()I
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findOrAdd(III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->access$000([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$100([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$200([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$300([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allValuesSameAs([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allocDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->build(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clear()V
+HSPLandroid/icu/util/MutableCodePointTrie;->compactData(I[IILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactIndex(ILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactTrie(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactWholeDataBlocks(ILandroid/icu/util/MutableCodePointTrie$AllSameBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->ensureHighStart(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->fillBlock(IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie;->findAllSameBlock([IIIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->findHighStart()I
+HSPLandroid/icu/util/MutableCodePointTrie;->findSameBlock([CII[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->fromCodePointMap(Landroid/icu/util/CodePointMap;)Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->getAllSameOverlap([IIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([II[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->isStartOfSomeFastBlock(I[II)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->maskValues(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->writeBlock(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->buildImmutable(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Ljava/lang/Object;
+HSPLandroid/icu/util/MutableCodePointTrie;->get(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->set(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->setRange(III)V
HSPLandroid/icu/util/SimpleTimeZone;-><init>(ILjava/lang/String;IIIIIIIIIII)V
HSPLandroid/icu/util/SimpleTimeZone;->clone()Ljava/lang/Object;
HSPLandroid/icu/util/SimpleTimeZone;->cloneAsThawed()Landroid/icu/util/TimeZone;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d7cca15..997ed25 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -76,7 +76,8 @@
* @attr ref android.R.styleable#AccessibilityService_notificationTimeout
* @attr ref android.R.styleable#AccessibilityService_packageNames
* @attr ref android.R.styleable#AccessibilityService_settingsActivity
- * @attr ref android.R.styleable#AccessibilityService_minimumUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
* @see AccessibilityService
* @see android.view.accessibility.AccessibilityEvent
* @see android.view.accessibility.AccessibilityManager
@@ -434,11 +435,14 @@
public boolean crashed;
/**
- * The minimum timeout in milliseconds that UI controls need to remain on the screen.
- *
- * @see #setMinimumUiTimeoutMillis
+ * A recommended timeout in milliseconds for non-interactive controls.
*/
- private int mMinimumUiTimeout;
+ private int mNonInteractiveUiTimeout;
+
+ /**
+ * A recommended timeout in milliseconds for interactive controls.
+ */
+ private int mInteractiveUiTimeout;
/**
* The component name the accessibility service.
@@ -544,8 +548,11 @@
notificationTimeout = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
0);
- mMinimumUiTimeout = asAttributes.getInt(
- com.android.internal.R.styleable.AccessibilityService_minimumUiTimeout,
+ mNonInteractiveUiTimeout = asAttributes.getInt(
+ com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout,
+ 0);
+ mInteractiveUiTimeout = asAttributes.getInt(
+ com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout,
0);
flags = asAttributes.getInt(
com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
@@ -616,7 +623,8 @@
packageNames = other.packageNames;
feedbackType = other.feedbackType;
notificationTimeout = other.notificationTimeout;
- mMinimumUiTimeout = other.mMinimumUiTimeout;
+ mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout;
+ mInteractiveUiTimeout = other.mInteractiveUiTimeout;
flags = other.flags;
}
@@ -775,26 +783,57 @@
}
/**
- * Set the minimum time that controls need to remain on the screen to support the user.
+ * Set the recommended time that non-interactive controls need to remain on the screen to
+ * support the user.
* <p>
- * <strong>This value can be dynamically set at runtime by
- * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+ * <strong>This value can be dynamically set at runtime by
+ * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
* </p>
*
* @param timeout The timeout in milliseconds.
+ *
+ * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
*/
- public void setMinimumUiTimeoutMillis(int timeout) {
- mMinimumUiTimeout = timeout;
+ public void setNonInteractiveUiTimeoutMillis(int timeout) {
+ mNonInteractiveUiTimeout = timeout;
}
/**
- * Get the minimum ui timeout.
+ * Get the recommended timeout for non-interactive controls.
*
- * @see #setMinimumUiTimeoutMillis
* @return The timeout in milliseconds.
+ *
+ * @see #setNonInteractiveUiTimeoutMillis(int)
*/
- public int getMinimumUiTimeoutMillis() {
- return mMinimumUiTimeout;
+ public int getNonInteractiveUiTimeoutMillis() {
+ return mNonInteractiveUiTimeout;
+ }
+
+ /**
+ * Set the recommended time that interactive controls need to remain on the screen to
+ * support the user.
+ * <p>
+ * <strong>This value can be dynamically set at runtime by
+ * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+ * </p>
+ *
+ * @param timeout The timeout in milliseconds.
+ *
+ * @see android.R.styleable#AccessibilityService_interactiveUiTimeout
+ */
+ public void setInteractiveUiTimeoutMillis(int timeout) {
+ mInteractiveUiTimeout = timeout;
+ }
+
+ /**
+ * Get the recommended timeout for interactive controls.
+ *
+ * @return The timeout in milliseconds.
+ *
+ * @see #setInteractiveUiTimeoutMillis(int)
+ */
+ public int getInteractiveUiTimeoutMillis() {
+ return mInteractiveUiTimeout;
}
/** {@hide} */
@@ -815,7 +854,8 @@
parcel.writeStringArray(packageNames);
parcel.writeInt(feedbackType);
parcel.writeLong(notificationTimeout);
- parcel.writeInt(mMinimumUiTimeout);
+ parcel.writeInt(mNonInteractiveUiTimeout);
+ parcel.writeInt(mInteractiveUiTimeout);
parcel.writeInt(flags);
parcel.writeInt(crashed ? 1 : 0);
parcel.writeParcelable(mComponentName, flagz);
@@ -833,7 +873,8 @@
packageNames = parcel.readStringArray();
feedbackType = parcel.readInt();
notificationTimeout = parcel.readLong();
- mMinimumUiTimeout = parcel.readInt();
+ mNonInteractiveUiTimeout = parcel.readInt();
+ mInteractiveUiTimeout = parcel.readInt();
flags = parcel.readInt();
crashed = parcel.readInt() != 0;
mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
@@ -884,7 +925,9 @@
stringBuilder.append(", ");
stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
stringBuilder.append(", ");
- stringBuilder.append("minimumUiTimeout: ").append(mMinimumUiTimeout);
+ stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout);
+ stringBuilder.append(", ");
+ stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout);
stringBuilder.append(", ");
appendFlags(stringBuilder, flags);
stringBuilder.append(", ");
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index f5d5e6e..7fe21b2 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.NonNull;
import android.util.SparseIntArray;
import com.android.internal.util.function.QuadFunction;
@@ -73,4 +74,21 @@
* access to app ops for their user.
*/
public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
+
+ /**
+ * Sets the app-ops mode for a certain app-op and uid.
+ *
+ * <p>Similar as {@link AppOpsManager#setMode} but does not require the package manager to be
+ * working. Hence this can be used very early during boot.
+ *
+ * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
+ *
+ * @param code The op code to set.
+ * @param uid The UID for which to set.
+ * @param packageName The package for which to set.
+ * @param mode The new mode to set.
+ * @param isPrivileged If the package is privileged
+ */
+ public abstract void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean isPrivileged);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6d464fb..4f4df5d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4457,6 +4457,7 @@
contentView.setViewVisibility(R.id.time, View.GONE);
contentView.setImageViewIcon(R.id.profile_badge, null);
contentView.setViewVisibility(R.id.profile_badge, View.GONE);
+ contentView.setViewVisibility(R.id.alerted_icon, View.GONE);
mN.mUsesStandardHeader = false;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e95f9ab..713f752 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -857,11 +857,17 @@
@Override
public BiometricManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- final IBinder binder =
- ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
- final IBiometricService service =
- IBiometricService.Stub.asInterface(binder);
- return new BiometricManager(ctx.getOuterContext(), service);
+ if (BiometricManager.hasBiometrics(ctx)) {
+ final IBinder binder =
+ ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
+ final IBiometricService service =
+ IBiometricService.Stub.asInterface(binder);
+ return new BiometricManager(ctx.getOuterContext(), service);
+ } else {
+ // Allow access to the manager when service is null. This saves memory
+ // on devices without biometric hardware.
+ return new BiometricManager(ctx.getOuterContext(), null);
+ }
}
});
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 8fddb99..cef21f6 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -38,4 +38,9 @@
void commit(in IntentSender statusReceiver, boolean forTransferred);
void transfer(in String packageName);
void abandon();
+ boolean isMultiPackage();
+ int[] getChildSessionIds();
+ void addChildSessionId(in int sessionId);
+ void removeChildSessionId(in int sessionId);
+ int getParentSessionId();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e9cfa78..8f90199 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -365,12 +365,14 @@
*/
public @NonNull Session openSession(int sessionId) throws IOException {
try {
- return new Session(mInstaller.openSession(sessionId));
+ try {
+ return new Session(mInstaller.openSession(sessionId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} catch (RuntimeException e) {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
}
}
@@ -769,9 +771,18 @@
* If an APK included in this session is already defined by the existing
* installation (for example, the same split name), the APK in this session
* will replace the existing APK.
+ * <p>
+ * In such a case that multiple packages need to be commited simultaneously,
+ * multiple sessions can be referenced by a single multi-package session.
+ * This session is created with no package name and calling
+ * {@link SessionParams#setMultiPackage()} with {@code true}. The
+ * individual session IDs can be added with {@link #addChildSessionId(int)}
+ * and commit of the multi-package session will result in all child sessions
+ * being committed atomically.
*/
public static class Session implements Closeable {
- private IPackageInstallerSession mSession;
+ /** {@hide} */
+ protected final IPackageInstallerSession mSession;
/** {@hide} */
public Session(IPackageInstallerSession session) {
@@ -1080,6 +1091,71 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * @return {@code true} if this session will commit more than one package when it is
+ * committed.
+ */
+ public boolean isMultiPackage() {
+ try {
+ return mSession.isMultiPackage();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the session ID of the multi-package session that this belongs to or
+ * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
+ */
+ public int getParentSessionId() {
+ try {
+ return mSession.getParentSessionId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the set of session IDs that will be committed atomically when this session is
+ * committed if this is a multi-package session or null if none exist.
+ */
+ @NonNull
+ public int[] getChildSessionIds() {
+ try {
+ return mSession.getChildSessionIds();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adds a session ID to the set of sessions that will be committed atomically
+ * when this session is committed.
+ *
+ * @param sessionId the session ID to add to this multi-package session.
+ */
+ public void addChildSessionId(int sessionId) {
+ try {
+ mSession.addChildSessionId(sessionId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes a session ID from the set of sessions that will be committed
+ * atomically when this session is committed.
+ *
+ * @param sessionId the session ID to remove from this multi-package session.
+ */
+ public void removeChildSessionId(int sessionId) {
+ try {
+ mSession.removeChildSessionId(sessionId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -1149,6 +1225,8 @@
public String[] grantedRuntimePermissions;
/** {@hide} */
public String installerPackageName;
+ /** {@hide} */
+ public boolean isMultiPackage;
/**
* Construct parameters for a new package install session.
@@ -1178,6 +1256,7 @@
volumeUuid = source.readString();
grantedRuntimePermissions = source.readStringArray();
installerPackageName = source.readString();
+ isMultiPackage = source.readBoolean();
}
/**
@@ -1392,6 +1471,18 @@
this.installerPackageName = installerPackageName;
}
+ /**
+ * Set this session to be the parent of a multi-package install.
+ *
+ * A multi-package install session contains no APKs and only references other install
+ * sessions via ID. When a multi-package session is committed, all of its children
+ * are committed to the system in an atomic manner. If any children fail to install,
+ * all of them do, including the multi-package session.
+ */
+ public void setMultiPackage() {
+ this.isMultiPackage = true;
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
@@ -1408,6 +1499,7 @@
pw.printPair("volumeUuid", volumeUuid);
pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
pw.printPair("installerPackageName", installerPackageName);
+ pw.printPair("isMultiPackage", isMultiPackage);
pw.println();
}
@@ -1433,6 +1525,7 @@
dest.writeString(volumeUuid);
dest.writeStringArray(grantedRuntimePermissions);
dest.writeString(installerPackageName);
+ dest.writeBoolean(isMultiPackage);
}
public static final Parcelable.Creator<SessionParams>
@@ -1454,6 +1547,12 @@
*/
public static class SessionInfo implements Parcelable {
+ /**
+ * A session ID that does not exist or is invalid.
+ */
+ public static final int INVALID_ID = -1;
+ /** {@hide} */
+ private static final int[] NO_SESSIONS = {};
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int sessionId;
@@ -1503,6 +1602,12 @@
public String[] grantedRuntimePermissions;
/** {@hide} */
public int installFlags;
+ /** {@hide} */
+ public boolean isMultiPackage;
+ /** {@hide} */
+ public int parentSessionId = INVALID_ID;
+ /** {@hide} */
+ public int[] childSessionIds = NO_SESSIONS;
/** {@hide} */
@UnsupportedAppUsage
@@ -1531,6 +1636,12 @@
referrerUri = source.readParcelable(null);
grantedRuntimePermissions = source.readStringArray();
installFlags = source.readInt();
+ isMultiPackage = source.readBoolean();
+ parentSessionId = source.readInt();
+ childSessionIds = source.createIntArray();
+ if (childSessionIds == null) {
+ childSessionIds = NO_SESSIONS;
+ }
}
/**
@@ -1784,6 +1895,30 @@
return createDetailsIntent();
}
+ /**
+ * Returns true if this session is a multi-package session containing references to other
+ * sessions.
+ */
+ public boolean isMultiPackage() {
+ return isMultiPackage;
+ }
+
+ /**
+ * Returns the parent multi-package session ID if this session belongs to one,
+ * {@link #INVALID_ID} otherwise.
+ */
+ public int getParentSessionId() {
+ return parentSessionId;
+ }
+
+ /**
+ * Returns the set of session IDs that will be committed when this session is commited if
+ * this session is a multi-package session.
+ */
+ public int[] getChildSessionIds() {
+ return childSessionIds;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1811,6 +1946,9 @@
dest.writeParcelable(referrerUri, flags);
dest.writeStringArray(grantedRuntimePermissions);
dest.writeInt(installFlags);
+ dest.writeBoolean(isMultiPackage);
+ dest.writeInt(parentSessionId);
+ dest.writeIntArray(childSessionIds);
}
public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 67b86c0..c1ac061 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -915,6 +915,11 @@
public static final int INSTALL_REASON_USER = 4;
/**
+ * @hide
+ */
+ public static final int INSTALL_UNKNOWN = 0;
+
+ /**
* Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
* on success.
*
@@ -2943,6 +2948,15 @@
public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6;
/**
+ * Permission flag: The permission has not been explicitly requested by
+ * the app but has been added automatically by the system. Revoke once
+ * the app does explicitly request it.
+ *
+ * @hide
+ */
+ public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7;
+
+ /**
* Mask for all permission flags.
*
* @hide
@@ -3593,7 +3607,10 @@
FLAG_PERMISSION_POLICY_FIXED,
FLAG_PERMISSION_REVOKE_ON_UPGRADE,
FLAG_PERMISSION_SYSTEM_FIXED,
- FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+ /*
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESED
+ */
})
@Retention(RetentionPolicy.SOURCE)
public @interface PermissionFlags {}
@@ -6133,6 +6150,7 @@
case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE";
case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED";
case FLAG_PERMISSION_REVIEW_REQUIRED: return "REVIEW_REQUIRED";
+ case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
default: return Integer.toString(flag);
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index dc33bde..7ef5264 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2435,7 +2435,7 @@
}
final int NP = PackageParser.NEW_PERMISSIONS.length;
- StringBuilder implicitPerms = null;
+ StringBuilder newPermsMsg = null;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
@@ -2443,19 +2443,20 @@
break;
}
if (!pkg.requestedPermissions.contains(npi.name)) {
- if (implicitPerms == null) {
- implicitPerms = new StringBuilder(128);
- implicitPerms.append(pkg.packageName);
- implicitPerms.append(": compat added ");
+ if (newPermsMsg == null) {
+ newPermsMsg = new StringBuilder(128);
+ newPermsMsg.append(pkg.packageName);
+ newPermsMsg.append(": compat added ");
} else {
- implicitPerms.append(' ');
+ newPermsMsg.append(' ');
}
- implicitPerms.append(npi.name);
+ newPermsMsg.append(npi.name);
pkg.requestedPermissions.add(npi.name);
+ pkg.implicitPermissions.add(npi.name);
}
}
- if (implicitPerms != null) {
- Slog.i(TAG, implicitPerms.toString());
+ if (newPermsMsg != null) {
+ Slog.i(TAG, newPermsMsg.toString());
}
@@ -2472,6 +2473,7 @@
final String perm = newPerms.get(in);
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
+ pkg.implicitPermissions.add(perm);
}
}
}
@@ -6394,6 +6396,9 @@
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
+ /** Permissions requested but not in the manifest. */
+ public final ArrayList<String> implicitPermissions = new ArrayList<>();
+
@UnsupportedAppUsage
public ArrayList<String> protectedBroadcasts;
@@ -6923,6 +6928,8 @@
dest.readStringList(requestedPermissions);
internStringArrayList(requestedPermissions);
+ dest.readStringList(implicitPermissions);
+ internStringArrayList(implicitPermissions);
protectedBroadcasts = dest.createStringArrayList();
internStringArrayList(protectedBroadcasts);
@@ -7087,6 +7094,7 @@
dest.writeParcelableList(instrumentation, flags);
dest.writeStringList(requestedPermissions);
+ dest.writeStringList(implicitPermissions);
dest.writeStringList(protectedBroadcasts);
// TODO: This doesn't work: b/64295061
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index fe00604..ff58c75 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.util.Slog;
@@ -64,6 +65,19 @@
private final Context mContext;
private final IBiometricService mService;
+ private final boolean mHasHardware;
+
+ /**
+ * @param context
+ * @return
+ * @hide
+ */
+ public static boolean hasBiometrics(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+ || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
+ || pm.hasSystemFeature(PackageManager.FEATURE_FACE);
+ }
/**
* @hide
@@ -73,6 +87,8 @@
public BiometricManager(Context context, IBiometricService service) {
mContext = context;
mService = service;
+
+ mHasHardware = hasBiometrics(context);
}
/**
@@ -93,8 +109,12 @@
throw e.rethrowFromSystemServer();
}
} else {
- Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
- return BIOMETRIC_ERROR_UNAVAILABLE;
+ if (!mHasHardware) {
+ return BIOMETRIC_ERROR_NO_HARDWARE;
+ } else {
+ Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
+ return BIOMETRIC_ERROR_UNAVAILABLE;
+ }
}
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index fc30eed..2ea7066 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -67,15 +67,14 @@
* such an old app asks for a location permission (i.e. the
* {@link SplitPermissionInfo#getSplitPermission()}), then the
* {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
- * {@{@link SplitPermissionInfo#getNewPermissions}) is added.
+ * {@link SplitPermissionInfo#getNewPermissions}) is added.
*
* <p>Note: Regular apps do not have to worry about this. The platform and permission controller
* automatically add the new permissions where needed.
*
* @return All permissions that are split.
*/
- public @NonNull
- List<SplitPermissionInfo> getSplitPermissions() {
+ public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
return SPLIT_PERMISSIONS;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index c0fa1de..3d93afd 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -509,6 +509,100 @@
private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
/**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set as the default value when a call was
+ * not blocked by a CallScreeningService or any other system call blocking method.
+ */
+ public static final int BLOCK_REASON_NOT_BLOCKED = 0;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked by a
+ * CallScreeningService. The {@link CallLog.Calls#CALL_SCREENING_COMPONENT_NAME} and
+ * {@link CallLog.Calls#CALL_SCREENING_APP_NAME} columns will indicate which call screening
+ * service was responsible for blocking the call.
+ */
+ public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * configured a contact to be sent directly to voicemail.
+ */
+ public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because it is
+ * in the BlockedNumbers provider.
+ */
+ public static final int BLOCK_REASON_BLOCKED_NUMBER = 3;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from unknown numbers.
+ */
+ public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from restricted numbers.
+ */
+ public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from pay phones.
+ */
+ public static final int BLOCK_REASON_PAY_PHONE = 6;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from numbers not in their contacts.
+ */
+ public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7;
+
+ /**
+ * The ComponentName of the CallScreeningService which blocked this call. Will be
+ * populated when the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
+
+ /**
+ * The name of the app which blocked a call. Will be populated when the
+ * {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}. Provided as a
+ * convenience so that the call log can still indicate which app blocked a call, even if
+ * that app is no longer installed.
+ * <P>Type: TEXT</P>
+ */
+ public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+
+ /**
+ * Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE},
+ * indicates the reason why a call is blocked.
+ * <P>Type: INTEGER</P>
+ *
+ * <p>
+ * Allowed values:
+ * <ul>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_BLOCKED}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_DIRECT_TO_VOICEMAIL}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_BLOCKED_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_UNKNOWN_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_RESTRICTED_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_PAY_PHONE}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_IN_CONTACTS}</li>
+ * </ul>
+ * </p>
+ */
+ public static final String BLOCK_REASON = "block_reason";
+
+ /**
* Adds a call to the call log.
*
* @param ci the CallerInfo object to get the target contact from. Can be null
@@ -530,12 +624,14 @@
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
- int presentation, int callType, int features, PhoneAccountHandle accountHandle,
+ int presentation, int callType, int features,
+ PhoneAccountHandle accountHandle,
long start, int duration, Long dataUsage) {
- return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
- presentation, callType, features, accountHandle, start, duration,
- dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
- /* is_read =*/ false);
+ return addCall(ci, context, number, "" /* postDialDigits */, "" /* viaNumber */,
+ presentation, callType, features, accountHandle, start, duration,
+ dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */,
+ false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */,
+ null /* callScreeningAppName */, null /* callScreeningComponentName */);
}
@@ -572,8 +668,10 @@
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
- features, accountHandle, start, duration, dataUsage, addForAllUsers,
- userToBeInsertedTo, /* is_read =*/ false);
+ features, accountHandle, start, duration, dataUsage, addForAllUsers,
+ userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED
+ /* callBlockReason */, null /* callScreeningAppName */,
+ null /* callScreeningComponentName */);
}
/**
@@ -602,8 +700,11 @@
* @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
* inserted to. null if it is inserted to the current user. The
* value is ignored if @{link addForAllUsers} is true.
- * @param is_read Flag to show if the missed call log has been read by the user or not.
+ * @param isRead Flag to show if the missed call log has been read by the user or not.
* Used for call log restore of missed calls.
+ * @param callBlockReason The reason why the call is blocked.
+ * @param callScreeningAppName The call screening application name which block the call.
+ * @param callScreeningComponentName The call screening component name which block the call.
*
* @result The URI of the call log entry belonging to the user that made or received this
* call. This could be of the shadow provider. Do not return it to non-system apps,
@@ -615,7 +716,8 @@
String postDialDigits, String viaNumber, int presentation, int callType,
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
- boolean is_read) {
+ boolean isRead, int callBlockReason, String callScreeningAppName,
+ String callScreeningComponentName) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
number, userToBeInsertedTo, addForAllUsers));
@@ -690,9 +792,13 @@
values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0);
if (callType == MISSED_TYPE) {
- values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
+ values.put(IS_READ, Integer.valueOf(isRead ? 1 : 0));
}
+ values.put(BLOCK_REASON, callBlockReason);
+ values.put(CALL_SCREENING_APP_NAME, callScreeningAppName);
+ values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
+
if ((ci != null) && (ci.contactIdOrZero > 0)) {
// Update usage information for the number associated with the contact ID.
// We need to use both the number and the ID for obtaining a data ID since other
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3b5dca9..8e4de9f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4895,6 +4895,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET);
MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_ENABLE);
MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_TIMEOUT);
@@ -6567,23 +6568,22 @@
public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
/**
- * Whether the user specifies a minimum ui timeout to override minimum ui timeout of
- * accessibility service
+ * Setting that specifies recommended timeout in milliseconds for controls
+ * which don't need user's interactions.
*
- * Type: int (0 for false, 1 for true)
* @hide
*/
- public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
- "accessibility_minimum_ui_timeout_enabled";
+ public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
+ "accessibility_non_interactive_ui_timeout_ms";
/**
- * Setting that specifies ui minimum timeout in milliseconds.
+ * Setting that specifies recommended timeout in milliseconds for controls
+ * which need user's interactions.
*
- * @see #ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED
* @hide
*/
- public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
- "accessibility_minimum_ui_timeout_ms";
+ public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
+ "accessibility_interactive_ui_timeout_ms";
/**
* List of the enabled print services.
@@ -8201,6 +8201,12 @@
"packages_to_clear_data_before_full_restore";
/**
+ * Setting to determine whether to use the new notification priority handling features.
+ * @hide
+ */
+ public static final String NOTIFICATION_NEW_INTERRUPTION_MODEL = "new_interruption_model";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -8312,8 +8318,9 @@
ZEN_SETTINGS_SUGGESTION_VIEWED,
CHARGING_SOUNDS_ENABLED,
CHARGING_VIBRATION_ENABLED,
- ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
- ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+ ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+ NOTIFICATION_NEW_INTERRUPTION_MODEL,
};
/**
@@ -8469,10 +8476,12 @@
VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
}
/**
@@ -9987,6 +9996,15 @@
"wifi_rtt_background_exec_gap_ms";
/**
+ * Indicate whether factory reset request is pending.
+ *
+ * Type: int (0 for false, 1 for true)
+ * @hide
+ */
+ public static final String WIFI_P2P_PENDING_FACTORY_RESET =
+ "wifi_p2p_pending_factory_reset";
+
+ /**
* Whether soft AP will shut down after a timeout period when no devices are connected.
*
* Type: int (0 for false, 1 for true)
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b8e0387..56e6aea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1461,6 +1461,7 @@
private boolean mShowBadge;
private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
private boolean mHidden;
+ private boolean mAudiblyAlerted;
private ArrayList<Notification.Action> mSmartActions;
private ArrayList<CharSequence> mSmartReplies;
@@ -1627,6 +1628,15 @@
}
/**
+ * Returns whether this notification alerted the user via sound or vibration.
+ *
+ * @return true if the notification alerted the user, false otherwise.
+ */
+ public boolean audiblyAlerted() {
+ return mAudiblyAlerted;
+ }
+
+ /**
* @hide
*/
@VisibleForTesting
@@ -1635,8 +1645,8 @@
CharSequence explanation, String overrideGroupKey,
NotificationChannel channel, ArrayList<String> overridePeople,
ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
- int userSentiment, boolean hidden, ArrayList<Notification.Action> smartActions,
- ArrayList<CharSequence> smartReplies) {
+ int userSentiment, boolean hidden, boolean audiblyAlerted,
+ ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies) {
mKey = key;
mRank = rank;
mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1652,6 +1662,7 @@
mShowBadge = showBadge;
mUserSentiment = userSentiment;
mHidden = hidden;
+ mAudiblyAlerted = audiblyAlerted;
mSmartActions = smartActions;
mSmartReplies = smartReplies;
}
@@ -1703,6 +1714,7 @@
private ArrayMap<String, Boolean> mShowBadge;
private ArrayMap<String, Integer> mUserSentiment;
private ArrayMap<String, Boolean> mHidden;
+ private ArrayMap<String, Boolean> mAudiblyAlerted;
private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;
private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies;
@@ -1733,8 +1745,8 @@
getVisibilityOverride(key), getSuppressedVisualEffects(key),
getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
- getShowBadge(key), getUserSentiment(key), getHidden(key), getSmartActions(key),
- getSmartReplies(key));
+ getShowBadge(key), getUserSentiment(key), getHidden(key),
+ getAudiblyAlerted(key), getSmartActions(key), getSmartReplies(key));
return rank >= 0;
}
@@ -1872,6 +1884,16 @@
return hidden == null ? false : hidden.booleanValue();
}
+ private boolean getAudiblyAlerted(String key) {
+ synchronized (this) {
+ if (mAudiblyAlerted == null) {
+ buildAudiblyAlertedLocked();
+ }
+ }
+ Boolean audiblyAlerted = mAudiblyAlerted.get(key);
+ return audiblyAlerted == null ? false : audiblyAlerted.booleanValue();
+ }
+
private ArrayList<Notification.Action> getSmartActions(String key) {
synchronized (this) {
if (mSmartActions == null) {
@@ -2007,6 +2029,11 @@
}
// Locked by 'this'
+ private void buildAudiblyAlertedLocked() {
+ mAudiblyAlerted = buildBooleanMapFromBundle(mRankingUpdate.getAudiblyAlerted());
+ }
+
+ // Locked by 'this'
private void buildSmartActions() {
Bundle smartActions = mRankingUpdate.getSmartActions();
mSmartActions = new ArrayMap<>(smartActions.size());
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index c67fad0..b561bfd 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -39,13 +39,14 @@
private final Bundle mHidden;
private final Bundle mSmartActions;
private final Bundle mSmartReplies;
+ private final Bundle mAudiblyAlerted;
public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
Bundle visibilityOverrides, Bundle suppressedVisualEffects,
int[] importance, Bundle explanation, Bundle overrideGroupKeys,
Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions,
- Bundle smartReplies) {
+ Bundle smartReplies, Bundle audiblyAlerted) {
mKeys = keys;
mInterceptedKeys = interceptedKeys;
mVisibilityOverrides = visibilityOverrides;
@@ -61,6 +62,7 @@
mHidden = hidden;
mSmartActions = smartActions;
mSmartReplies = smartReplies;
+ mAudiblyAlerted = audiblyAlerted;
}
public NotificationRankingUpdate(Parcel in) {
@@ -80,6 +82,7 @@
mHidden = in.readBundle();
mSmartActions = in.readBundle();
mSmartReplies = in.readBundle();
+ mAudiblyAlerted = in.readBundle();
}
@Override
@@ -104,6 +107,7 @@
out.writeBundle(mHidden);
out.writeBundle(mSmartActions);
out.writeBundle(mSmartReplies);
+ out.writeBundle(mAudiblyAlerted);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -176,4 +180,8 @@
public Bundle getSmartReplies() {
return mSmartReplies;
}
+
+ public Bundle getAudiblyAlerted() {
+ return mAudiblyAlerted;
+ }
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 769dd1b..b047ef7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,7 +42,6 @@
private static final Map<String, String> DEFAULT_FLAGS;
static {
DEFAULT_FLAGS = new HashMap<>();
- DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 81da76d..fa30221 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -61,6 +61,7 @@
private View mCameraIcon;
private View mMicIcon;
private View mAppOps;
+ private View mAudiblyAlertedIcon;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -121,6 +122,7 @@
mMicIcon = findViewById(com.android.internal.R.id.mic);
mOverlayIcon = findViewById(com.android.internal.R.id.overlay);
mAppOps = findViewById(com.android.internal.R.id.app_ops);
+ mAudiblyAlertedIcon = findViewById(com.android.internal.R.id.alerted_icon);
}
@Override
@@ -216,6 +218,11 @@
layoutRight = end - paddingEnd;
end = layoutLeft = layoutRight - child.getMeasuredWidth();
}
+ if (child == mAudiblyAlertedIcon) {
+ int paddingEnd = mContentEndMargin;
+ layoutRight = end - paddingEnd;
+ end = layoutLeft = layoutRight - child.getMeasuredWidth();
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
int ltrLeft = layoutLeft;
layoutLeft = getWidth() - layoutRight;
@@ -337,6 +344,11 @@
? View.VISIBLE : View.GONE);
}
+ /** Updates icon visibility based on the noisiness of the notification. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
+ }
+
private void updateExpandButton() {
int drawableId;
int contentDescriptionId;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a7d0cfb..88b9c80 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -54,6 +55,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -117,6 +120,39 @@
public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
"com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
+ /**
+ * Annotations for content flag of UI.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "FLAG_CONTENT_" }, value = {
+ FLAG_CONTENT_ICONS,
+ FLAG_CONTENT_TEXT,
+ FLAG_CONTENT_CONTROLS
+ })
+ public @interface ContentFlag {}
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains icons.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_ICONS = 1;
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains text.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_TEXT = 2;
+
+ /**
+ * Use this flag to indicate the content of a UI that times out contains interactive controls.
+ *
+ * @see #getRecommendedTimeoutMillis(int, int)
+ */
+ public static final int FLAG_CONTENT_CONTROLS = 4;
+
@UnsupportedAppUsage
static final Object sInstanceSync = new Object();
@@ -142,7 +178,8 @@
int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
- int mMinimumUiTimeout;
+ int mInteractiveUiTimeout;
+ int mNonInteractiveUiTimeout;
boolean mIsTouchExplorationEnabled;
@@ -304,7 +341,9 @@
}
@Override
- public void notifyServicesStateChanged() {
+ public void notifyServicesStateChanged(long updatedUiTimeout) {
+ updateUiTimeout(updatedUiTimeout);
+
final ArrayMap<AccessibilityServicesStateChangeListener, Handler> listeners;
synchronized (mLock) {
if (mServicesStateChangeListeners.isEmpty()) {
@@ -326,11 +365,6 @@
public void setRelevantEventTypes(int eventTypes) {
mRelevantEventTypes = eventTypes;
}
-
- @Override
- public void setMinimumUiTimeout(int uiTimeout) {
- mMinimumUiTimeout = uiTimeout;
- }
};
/**
@@ -840,16 +874,35 @@
}
/**
- * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+ * Get the recommended timeout for changes to the UI needed by this user. Controls should remain
* on the screen for at least this long to give users time to react. Some users may need
* extra time to review the controls, or to reach them, or to activate assistive technology
* to activate the controls automatically.
+ * <p>
+ * Use the combination of content flags to indicate contents of UI. For example, use
+ * {@code FLAG_CONTENT_ICONS | FLAG_CONTENT_TEXT} for message notification which contains
+ * icons and text, or use {@code FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS} for button dialog
+ * which contains text and button controls.
+ * <p/>
*
- * @return The minimum ui timeout for the current user in milliseconds.
- * {@link Integer#MAX_VALUE} if timeout is infinite.
+ * @param originalTimeout The timeout appropriate for users with no accessibility needs.
+ * @param uiContentFlags The combination of flags {@link #FLAG_CONTENT_ICONS},
+ * {@link #FLAG_CONTENT_TEXT} or {@link #FLAG_CONTENT_CONTROLS} to
+ * indicate the contents of UI.
+ * @return The recommended UI timeout for the current user in milliseconds.
*/
- public int getMinimumUiTimeoutMillis() {
- return mMinimumUiTimeout;
+ public int getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags) {
+ boolean hasControls = (uiContentFlags & FLAG_CONTENT_CONTROLS) != 0;
+ boolean hasIconsOrText = (uiContentFlags & FLAG_CONTENT_ICONS) != 0
+ || (uiContentFlags & FLAG_CONTENT_TEXT) != 0;
+ int recommendedTimeout = originalTimeout;
+ if (hasControls) {
+ recommendedTimeout = Math.max(recommendedTimeout, mInteractiveUiTimeout);
+ }
+ if (hasIconsOrText) {
+ recommendedTimeout = Math.max(recommendedTimeout, mNonInteractiveUiTimeout);
+ }
+ return recommendedTimeout;
}
/**
@@ -1192,7 +1245,7 @@
final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
setStateLocked(IntPair.first(userStateAndRelevantEvents));
mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
- mMinimumUiTimeout = service.getMinimumUiTimeout();
+ updateUiTimeout(service.getRecommendedTimeoutMillis());
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -1266,6 +1319,17 @@
}
/**
+ * Update interactive and non-interactive UI timeout.
+ *
+ * @param uiTimeout A pair of {@code int}s. First integer for interactive one, and second
+ * integer for non-interactive one.
+ */
+ private void updateUiTimeout(long uiTimeout) {
+ mInteractiveUiTimeout = IntPair.first(uiTimeout);
+ mNonInteractiveUiTimeout = IntPair.second(uiTimeout);
+ }
+
+ /**
* Determines if the accessibility button within the system navigation area is supported.
*
* @return {@code true} if the accessibility button is supported on this device,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 61a8a1da..2767a82 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -76,5 +76,5 @@
// System process only
boolean sendFingerprintGesture(int gestureKeyCode);
- int getMinimumUiTimeout();
+ long getRecommendedTimeoutMillis();
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index d2ddca3..94b9ad1 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,9 +26,7 @@
void setState(int stateFlags);
- void notifyServicesStateChanged();
+ void notifyServicesStateChanged(long updatedUiTimeout);
void setRelevantEventTypes(int eventTypes);
-
- void setMinimumUiTimeout(int uiTimeout);
}
diff --git a/core/java/android/view/inspector/InspectableChildren.java b/core/java/android/view/inspector/InspectableChildren.java
new file mode 100644
index 0000000..de8fa29
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableChildren.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter for an inspectable node's inspectable children.
+ *
+ * This annotation can be applied to any getter that returns a collection of objects, either an
+ * array, an {@link Iterable} or a {@link java.util.Iterator}. The getter may return null, which
+ * will be treated as an empty collection. Additionally, the inspector will discard any null
+ * entries in the collection.
+ *
+ * By default, this annotation is inherited. At runtime, the inspector introspects on the class
+ * hierachy and uses the annotated getter from the bottommost class, if different from any
+ * annoated getters of the parent class. If a class inherits from a parent class with an annotated
+ * getter, but does not include this annotation, the child class will be traversed using the
+ * getter annotated on the parent. This holds true even if the child class overrides the getter.
+ *
+ * @see InspectionHelper#traverseChildren(Object, ChildTraverser)
+ * @see InspectionHelper#hasChildTraversal()
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableChildren {
+}
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
new file mode 100644
index 0000000..716409c
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableNodeName.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.view.inspector;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks the node name to display to a developer in the inspection tree.
+ *
+ * This annotation is optional to marking a class as inspectable. If it is omitted, the node name
+ * will be inferred using the semantics of {@link Class#getSimpleName()}. The fully qualified class
+ * name is always available in the tree, this is for display purposes only. If a class is inflated
+ * from XML and the tag it inflates from does not match its simple name, this annotation should be
+ * used to inform the inspector to display the XML tag name in the inspection tree view.
+ *
+ * This annotation does not inherit. If a class extends an annotated parent class, but does not
+ * annotate itself, its node name will be inferred from its Java name.
+ *
+ * @see InspectionHelper#getNodeName()
+ * @hide
+ */
+@Target({TYPE})
+@Retention(SOURCE)
+public @interface InspectableNodeName {
+ /**
+ * The display name for nodes of this type.
+ *
+ * @return The name for nodes of this type
+ */
+ String value();
+}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
new file mode 100644
index 0000000..b0fd503
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter of a property on an inspectable node.
+ *
+ * This annotation is inherited by default. If a child class doesn't add it to a getter, but a
+ * parent class does, the property will be inspected, even if the child overrides the definition
+ * of the getter. If a child class defines a property of the same name of a property on the parent
+ * but on a different getter, the inspector will use the child's getter when inspecting instances
+ * of the child, and the parent's otherwise.
+ *
+ * @see InspectionHelper#mapProperties(PropertyMapper)
+ * @see InspectionHelper#readProperties(Object, PropertyReader)
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableProperty {
+ /**
+ * The name of the property.
+ *
+ * If left empty (the default), the property name will be inferred from the name of the getter
+ * method.
+ *
+ * @return The name of the property.
+ */
+ String value() default "";
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f96f088..5b1544b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3928,6 +3928,7 @@
SelectionModifierCursorController selectionController = getSelectionController();
if (selectionController.mStartHandle == null) {
// As these are for initializing selectionController, hide() must be called.
+ loadHandleDrawables(false /* overwrite */);
selectionController.initHandles();
selectionController.hide();
}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 5433393..3a908dc 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -64,5 +64,8 @@
// OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent)
BIOMETRIC_ENROLL_ACTIVITY = 1586;
+
+ // OPEN: Settings > Privacy
+ TOP_LEVEL_PRIVACY = 1587;
}
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3ead633..f8acc33 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,8 +72,10 @@
// List of the accessibility services to which the user has granted
// permission to put the device into touch exploration mode.
optional SettingProto touch_exploration_granted_accessibility_services = 31;
- optional SettingProto minimum_ui_timeout_enabled = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto minimum_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 32; // minimum_ui_timeout_enabled
+ reserved 33; // minimum_ui_timeout_ms
+ optional SettingProto non_interactive_ui_timeout_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto interactive_ui_timeout_ms = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/res/res/drawable/ic_notifications_alerted.xml b/core/res/res/drawable/ic_notifications_alerted.xml
new file mode 100644
index 0000000..4bfac37
--- /dev/null
+++ b/core/res/res/drawable/ic_notifications_alerted.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"
+ android:fillColor="#FF000000" />
+</vector>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 8b1f28b..4ee9731 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -126,6 +126,19 @@
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
/>
+ <ImageView
+ android:id="@+id/alerted_icon"
+ android:layout_width="@dimen/notification_alerted_size"
+ android:layout_height="@dimen/notification_alerted_size"
+ android:layout_gravity="center"
+ android:layout_marginStart="4dp"
+ android:paddingTop="1dp"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_alerted_content_description"
+ android:src="@drawable/ic_notifications_alerted"
+ android:tint="@color/notification_secondary_text_color_light"
+ />
<LinearLayout
android:id="@+id/app_ops"
android:layout_height="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a25c998..68ec342 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3587,11 +3587,22 @@
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="notificationTimeout" format="integer" />
- <!-- The minimum timeout in milliseconds that UI controls need to remain on the screen.
+ <!-- A recommended timeout in milliseconds used in
+ {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+ android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+ to return a suitable value for UIs that do not include interactive controls.
This setting can be changed at runtime by calling
{@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
- <attr name="minimumUiTimeout" format="integer" />
+ <attr name="nonInteractiveUiTimeout" format="integer" />
+ <!-- A recommended timeout in milliseconds used in
+ {@link android.view.accessibility.AccessibilityManager#getRecommendedTimeoutMillis(int, int)
+ android.view.accessibility.AccessibilityManager.getRecommendedTimeoutMillis(int, int)}
+ to return a suitable value for interactive controls.
+ This setting can be changed at runtime by calling
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ <attr name="interactiveUiTimeout" format="integer" />
<!-- Additional flags as specified in
{@link android.accessibilityservice.AccessibilityServiceInfo}.
This setting can be changed at runtime by calling
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a8c78a6..bca72f4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2793,7 +2793,7 @@
<item>LPP_PROFILE=0</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
<!-- Sprint need a 70 ms delay for 3way call -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ba483fb..b65c0fd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -426,6 +426,9 @@
<!-- Size of the profile badge for notifications -->
<dimen name="notification_badge_size">12dp</dimen>
+ <!-- Size of the alerted icon for notifications -->
+ <dimen name="notification_alerted_size">18dp</dimen>
+
<!-- Keyguard dimensions -->
<!-- TEMP -->
<dimen name="kg_security_panel_height">600dp</dimen>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index a0c02ed..c1ca33e 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -44,9 +44,10 @@
<dimen name="car_headline3_size">24sp</dimen>
<dimen name="car_headline4_size">20sp</dimen>
<dimen name="car_body1_size">32sp</dimen>
- <dimen name="car_body2_size">26sp</dimen>
- <dimen name="car_body3_size">16sp</dimen>
- <dimen name="car_body4_size">14sp</dimen>
+ <dimen name="car_body2_size">28sp</dimen>
+ <dimen name="car_body3_size">26sp</dimen>
+ <dimen name="car_body4_size">24sp</dimen>
+ <!-- car_body5_size is deprecated -->
<dimen name="car_body5_size">18sp</dimen>
<dimen name="car_label1_size">26sp</dimen>
<dimen name="car_label2_size">64sp</dimen>
@@ -85,6 +86,7 @@
<dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
<dimen name="car_button_radius">@dimen/car_radius_1</dimen>
<dimen name="car_pill_button_size">56dp</dimen>
+ <dimen name="car_touch_target_size">76dp</dimen>
<!-- Seekbar -->
<dimen name="car_seekbar_height">6dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e1c5df3..15f29ce 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,12 +2912,13 @@
<public name="supportsAmbientMode" />
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />
- <public name="minimumUiTimeout" />
+ <public name="nonInteractiveUiTimeout" />
<public name="isLightTheme" />
<public name="isSplitRequired" />
<public name="textLocale" />
<public name="settingsSliceUri" />
<public name="shell" />
+ <public name="interactiveUiTimeout" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8b7cafb..8d3992d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4820,6 +4820,9 @@
<!-- Content description of the work profile icon in the notification. -->
<string name="notification_work_profile_content_description">Work profile</string>
+ <!-- Content description of the alerting icon in the notification. [CHAR_LIMIT=NONE] -->
+ <string name="notification_alerted_content_description">Alerted</string>
+
<!-- Content description of the expand button icon in the notification when collaped.-->
<string name="expand_button_content_description_collapsed">Expand</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 670a4a2..5418e03 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -215,6 +215,7 @@
<java-symbol type="id" name="pin_error_message" />
<java-symbol type="id" name="timePickerLayout" />
<java-symbol type="id" name="profile_badge" />
+ <java-symbol type="id" name="alerted_icon" />
<java-symbol type="id" name="transitionPosition" />
<java-symbol type="id" name="selection_start_handle" />
<java-symbol type="id" name="selection_end_handle" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d5dc903..3342266 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -497,6 +497,7 @@
Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
Settings.Global.WIFI_ON,
Settings.Global.WIFI_P2P_DEVICE_NAME,
+ Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET,
Settings.Global.WIFI_REENABLE_DELAY_MS,
Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS,
Settings.Global.WIFI_SAVED_STATE,
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 18b41fa..3c44916 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -149,9 +149,13 @@
}
/**
- * Returns the alpha value of this drawable's color.
+ * Returns the alpha value of this drawable's color. Note this may not be the same alpha value
+ * provided in {@link Drawable#setAlpha(int)}. Instead this will return the alpha of the color
+ * combined with the alpha provided by setAlpha
*
* @return A value between 0 and 255.
+ *
+ * @see ColorDrawable#setAlpha(int)
*/
@Override
public int getAlpha() {
@@ -159,7 +163,9 @@
}
/**
- * Sets the color's alpha value.
+ * Applies the given alpha to the underlying color. Note if the color already has
+ * an alpha applied to it, this will apply this alpha to the existing value instead of
+ * overwriting it.
*
* @param alpha The alpha value to set, between 0 and 255.
*/
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e1f7263..caf610b 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -934,11 +934,13 @@
* do account for the value of {@link #setAlpha}, but the general behavior is dependent
* upon the implementation of the subclass.
*
+ * @deprecated This method is no longer used in graphics optimizations
+ *
* @return int The opacity class of the Drawable.
*
* @see android.graphics.PixelFormat
*/
- public abstract @PixelFormat.Opacity int getOpacity();
+ @Deprecated public abstract @PixelFormat.Opacity int getOpacity();
/**
* Return the appropriate opacity value for two source opacities. If
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index a028515..59abad4 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1709,13 +1709,13 @@
struct resource_name
{
- const char16_t* package;
+ const char16_t* package = NULL;
size_t packageLen;
- const char16_t* type;
- const char* type8;
+ const char16_t* type = NULL;
+ const char* type8 = NULL;
size_t typeLen;
- const char16_t* name;
- const char* name8;
+ const char16_t* name = NULL;
+ const char* name8 = NULL;
size_t nameLen;
};
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 9eb4a13..26d2896 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -94,15 +94,15 @@
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
ResTable::resource_name res_name;
- ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, false, &res_name));
+ ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, true, &res_name));
ASSERT_TRUE(res_name.package != NULL);
ASSERT_TRUE(res_name.type != NULL);
- ASSERT_TRUE(res_name.name != NULL);
+ ASSERT_TRUE(res_name.name8 != NULL);
EXPECT_EQ(String16("com.android.basic"), String16(res_name.package, res_name.packageLen));
EXPECT_EQ(String16("array"), String16(res_name.type, res_name.typeLen));
- EXPECT_EQ(String16("integerArray1"), String16(res_name.name, res_name.nameLen));
+ EXPECT_EQ(String8("integerArray1"), String8(res_name.name8, res_name.nameLen));
}
constexpr const uint32_t kNonOverlaidResourceId = 0x7fff0000u;
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 05dc340..c58bcb3 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -139,7 +139,7 @@
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
uint32_t flags = paint->getFlags();
- SkFontHinting hinting = (SkFontHinting)paint->getHinting();
+ unsigned hinting = static_cast<unsigned>(paint->getHinting());
// select only flags that might affect text layout
flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag |
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 2b5dea1..47ab7fa 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -34,7 +34,6 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;
@@ -835,46 +834,29 @@
return null;
}
- // Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
- @GuardedBy("mRoutingChangeListeners")
- private void enableNativeRoutingCallbacksLocked(boolean enabled) {
- if (mRoutingChangeListeners.size() == 0) {
- native_enableDeviceCallback(enabled);
- }
- }
-
- // The list of AudioRouting.OnRoutingChangedListener interfaces added with
- // addOnRoutingChangedListener by an app to receive (re)routing notifications.
- @GuardedBy("mRoutingChangeListeners")
- private ArrayMap<AudioRouting.OnRoutingChangedListener,
- NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
-
@Override
public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
Handler handler) {
- synchronized (mRoutingChangeListeners) {
- if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- enableNativeRoutingCallbacksLocked(true);
- mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : mTaskHandler));
- }
+ if (listener == null) {
+ throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL");
}
+ RoutingDelegate routingDelegate = new RoutingDelegate(this, listener, handler);
+ native_addDeviceCallback(routingDelegate);
}
@Override
public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
- synchronized (mRoutingChangeListeners) {
- if (mRoutingChangeListeners.containsKey(listener)) {
- mRoutingChangeListeners.remove(listener);
- enableNativeRoutingCallbacksLocked(false);
- }
+ if (listener == null) {
+ throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL");
}
+ native_removeDeviceCallback(listener);
}
private native final boolean native_setOutputDevice(int deviceId);
private native final int native_getRoutedDeviceId();
- private native final void native_enableDeviceCallback(boolean enabled);
+ private native void native_addDeviceCallback(RoutingDelegate rd);
+ private native void native_removeDeviceCallback(
+ AudioRouting.OnRoutingChangedListener listener);
@Override
public Object setWakeMode(Context context, int mode) {
@@ -1614,7 +1596,6 @@
private static final int MEDIA_SUBTITLE_DATA = 201;
private static final int MEDIA_META_DATA = 202;
private static final int MEDIA_DRM_INFO = 210;
- private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private class TaskHandler extends Handler {
private MediaPlayer2Impl mMediaPlayer;
@@ -1946,18 +1927,6 @@
break;
}
- case MEDIA_AUDIO_ROUTING_CHANGED:
- {
- AudioManager.resetAudioPortGeneration();
- synchronized (mRoutingChangeListeners) {
- for (NativeRoutingEventHandlerDelegate delegate
- : mRoutingChangeListeners.values()) {
- delegate.notifyClient();
- }
- }
- return;
- }
-
default:
{
Log.e(TAG, "Unknown message type " + msg.what);
diff --git a/media/java/android/media/RoutingDelegate.java b/media/java/android/media/RoutingDelegate.java
new file mode 100644
index 0000000..2359813
--- /dev/null
+++ b/media/java/android/media/RoutingDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.media;
+
+import android.os.Handler;
+
+class RoutingDelegate implements AudioRouting.OnRoutingChangedListener {
+ private AudioRouting mAudioRouting;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ RoutingDelegate(final AudioRouting audioRouting,
+ final AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ mAudioRouting = audioRouting;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler;
+ }
+
+ public AudioRouting.OnRoutingChangedListener getListener() {
+ return mOnRoutingChangedListener;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ @Override
+ public void onRoutingChanged(AudioRouting router) {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mAudioRouting);
+ }
+ }
+}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index aa9e3d2..67005be 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1324,15 +1324,30 @@
return mp->getRoutedDeviceId();
}
-static void android_media_MediaPlayer2_enableDeviceCallback(
- JNIEnv* env, jobject thiz, jboolean enabled)
+static void android_media_MediaPlayer2_addDeviceCallback(
+ JNIEnv* env, jobject thiz, jobject routingDelegate)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
return;
}
- status_t status = mp->enableAudioDeviceCallback(enabled);
+ status_t status = mp->addAudioDeviceCallback(routingDelegate);
+ if (status != NO_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ ALOGE("enable device callback failed: %d", status);
+ }
+}
+
+static void android_media_MediaPlayer2_removeDeviceCallback(
+ JNIEnv* env, jobject thiz, jobject listener)
+{
+ sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return;
+ }
+
+ status_t status = mp->removeAudioDeviceCallback(listener);
if (status != NO_ERROR) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
ALOGE("enable device callback failed: %d", status);
@@ -1457,7 +1472,9 @@
// AudioRouting
{"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer2_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer2_getRoutedDeviceId},
- {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer2_enableDeviceCallback},
+ {"native_addDeviceCallback", "(Landroid/media/RoutingDelegate;)V", (void *)android_media_MediaPlayer2_addDeviceCallback},
+ {"native_removeDeviceCallback", "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V",
+ (void *)android_media_MediaPlayer2_removeDeviceCallback},
// StreamEventCallback for JAudioTrack
{"native_stream_event_onTearDown", "(JJ)V", (void *)android_media_MediaPlayer2_native_on_tear_down},
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index 8fee822..6f437bd5 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -15,6 +15,7 @@
*/
package android.ext.services.notification;
+import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -148,6 +149,18 @@
return Objects.equals(getNotification().category, category);
}
+ /**
+ * Similar to {@link #isCategory(String)}, but checking the public version of the notification,
+ * if available.
+ */
+ public boolean isPublicVersionCategory(String category) {
+ Notification publicVersion = getNotification().publicVersion;
+ if (publicVersion == null) {
+ return false;
+ }
+ return Objects.equals(publicVersion.category, category);
+ }
+
public boolean isAudioAttributesUsage(int usage) {
return mAttributes != null && mAttributes.getUsage() == usage;
}
@@ -175,9 +188,9 @@
}
protected boolean isMessaging() {
- return isCategory(Notification.CATEGORY_MESSAGE)
- || hasStyle(Notification.MessagingStyle.class)
- || hasInlineReply();
+ return isCategory(CATEGORY_MESSAGE)
+ || isPublicVersionCategory(CATEGORY_MESSAGE)
+ || hasStyle(Notification.MessagingStyle.class);
}
public boolean hasInlineReply() {
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 37a98fd..b2fc417 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -19,23 +19,22 @@
import android.annotation.Nullable;
import android.app.Notification;
import android.app.RemoteAction;
-import android.app.RemoteInput;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
-import android.os.SystemProperties;
-import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
public class SmartActionsHelper {
private static final ArrayList<Notification.Action> EMPTY_ACTION_LIST = new ArrayList<>();
@@ -50,12 +49,18 @@
private static final int MAX_ACTION_EXTRACTION_TEXT_LENGTH = 400;
private static final int MAX_ACTIONS_PER_LINK = 1;
private static final int MAX_SMART_ACTIONS = Notification.MAX_ACTION_BUTTONS;
- // Allow us to test out smart reply with dumb suggestions, it is disabled by default.
- // TODO: Removed this once we have the model.
- private static final String SYS_PROP_SMART_REPLIES_EXPERIMENT =
- "persist.sys.smart_replies_experiment";
+ private static final int MAX_SUGGESTED_REPLIES = 3;
- SmartActionsHelper() {}
+ private static final ConversationActions.TypeConfig TYPE_CONFIG =
+ new ConversationActions.TypeConfig.Builder().setIncludedTypes(
+ Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+ .includeTypesFromTextClassifier(false)
+ .build();
+ private static final List<String> HINTS =
+ Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
+
+ SmartActionsHelper() {
+ }
/**
* Adds action adjustments based on the notification contents.
@@ -92,8 +97,31 @@
if (context == null) {
return EMPTY_REPLY_LIST;
}
- // TODO: replaced this with our model when it is ready.
- return new ArrayList<>(Arrays.asList("Yes, please", "No, thanks"));
+ TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class);
+ if (tcm == null) {
+ return EMPTY_REPLY_LIST;
+ }
+ CharSequence text = getMostSalientActionText(entry.getNotification());
+ ConversationActions.Message message =
+ new ConversationActions.Message.Builder()
+ .setText(text)
+ .build();
+
+ ConversationActions.Request request =
+ new ConversationActions.Request.Builder(Collections.singletonList(message))
+ .setMaxSuggestions(MAX_SUGGESTED_REPLIES)
+ .setHints(HINTS)
+ .setTypeConfig(TYPE_CONFIG)
+ .build();
+
+ TextClassifier textClassifier = tcm.getTextClassifier();
+ List<ConversationActions.ConversationAction> conversationActions =
+ textClassifier.suggestConversationActions(request).getConversationActions();
+
+ return conversationActions.stream()
+ .map(conversationAction -> conversationAction.getTextReply())
+ .filter(textReply -> !TextUtils.isEmpty(textReply))
+ .collect(Collectors.toCollection(ArrayList::new));
}
/**
@@ -124,20 +152,30 @@
}
private boolean isEligibleForReplyAdjustment(@NonNull NotificationEntry entry) {
- if (!SystemProperties.getBoolean(SYS_PROP_SMART_REPLIES_EXPERIMENT, false)) {
+ if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
return false;
}
- Notification notification = entry.getNotification();
- if (notification.actions == null) {
+ String pkg = entry.getSbn().getPackageName();
+ if (TextUtils.isEmpty(pkg) || pkg.equals("android")) {
return false;
}
- return entry.hasInlineReply();
+ // For now, we are only interested in messages.
+ if (!entry.isMessaging()) {
+ return false;
+ }
+ // Does not make sense to provide suggested replies if it is not something that can be
+ // replied.
+ if (!entry.hasInlineReply()) {
+ return false;
+ }
+ return true;
}
/** Returns the text most salient for action extraction in a notification. */
@Nullable
private CharSequence getMostSalientActionText(@NonNull Notification notification) {
/* If it's messaging style, use the most recent message. */
+ // TODO: Use the last few X messages instead and take the Person object into consideration.
Parcelable[] messages = notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
if (messages != null && messages.length != 0) {
Bundle lastMessage = (Bundle) messages[messages.length - 1];
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 508adbd..e2a34f4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -21,35 +21,47 @@
<!-- Toast message when Wi-Fi cannot scan for networks -->
<string name="wifi_fail_to_scan">Can\'t scan for networks</string>
<!-- Do not translate. Concise terminology for wifi with WEP security -->
- <string name="wifi_security_short_wep">WEP</string>
+ <string name="wifi_security_short_wep" translatable="false">WEP</string>
<!-- Do not translate. Concise terminology for wifi with WPA security -->
- <string name="wifi_security_short_wpa">WPA</string>
+ <string name="wifi_security_short_wpa" translatable="false">WPA</string>
<!-- Do not translate. Concise terminology for wifi with WPA2 security -->
- <string name="wifi_security_short_wpa2">WPA2</string>
+ <string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
<!-- Do not translate. Concise terminology for wifi with both WPA/WPA2 security -->
- <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
+ <string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
<!-- Do not translate. Concise terminology for wifi with unknown PSK type -->
- <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
+ <string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_short_eap">802.1x</string>
+ <string name="wifi_security_short_eap" translatable="false">802.1x</string>
+ <!-- Do not translate. Concise terminology for wifi with WPA3 security -->
+ <string name="wifi_security_short_sae" translatable="false">WPA3</string>
+ <!-- Do not translate. Concise terminology for wifi with OWE security -->
+ <string name="wifi_security_short_owe" translatable="false">OWE</string>
+ <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security -->
+ <string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B</string>
<!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
- <string name="wifi_security_none">None</string>
+ <string name="wifi_security_none" translatable="false">None</string>
<!-- Do not translate. Terminology for wifi with WEP security -->
- <string name="wifi_security_wep">WEP</string>
+ <string name="wifi_security_wep" translatable="false">WEP</string>
<!-- Do not translate. Terminology for wifi with WPA security -->
- <string name="wifi_security_wpa">WPA PSK</string>
+ <string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
<!-- Do not translate. Terminology for wifi with WPA2 security -->
- <string name="wifi_security_wpa2">WPA2 PSK</string>
+ <string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
<!-- Do not translate. Terminology for wifi with both WPA/WPA2 security, or unknown -->
- <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
+ <string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
<!-- Do not translate. Terminology for wifi with unknown PSK type -->
- <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
+ <string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_eap">802.1x EAP</string>
+ <string name="wifi_security_eap" translatable="false">WPA/WPA2-Enterprise</string>
<!-- Do not translate. Concise terminology for Passpoint network -->
- <string name="wifi_security_passpoint">Passpoint</string>
+ <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
+ <!-- Do not translate. Terminology for wifi with WPA3 security -->
+ <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
+ <!-- Do not translate. Terminology for wifi with OWE security -->
+ <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
+ <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security -->
+ <string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise</string>
<!-- Summary for the remembered network. -->
<string name="wifi_remembered">Saved</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index dd8bfda..92fd868 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -51,6 +51,8 @@
public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
public static final String CATEGORY_NIGHT_DISPLAY =
"com.android.settings.category.ia.night_display";
+ public static final String CATEGORY_PRIVACY =
+ "com.android.settings.category.ia.privacy";
public static final Map<String, String> KEY_COMPAT_MAP;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e950e8e..523361d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -158,9 +158,12 @@
* These values are matched in string arrays -- changes must be kept in sync
*/
public static final int SECURITY_NONE = 0;
- public static final int SECURITY_WEP = 1;
- public static final int SECURITY_PSK = 2;
- public static final int SECURITY_EAP = 3;
+ public static final int SECURITY_OWE = 1;
+ public static final int SECURITY_WEP = 2;
+ public static final int SECURITY_PSK = 3;
+ public static final int SECURITY_SAE = 4;
+ public static final int SECURITY_EAP = 5;
+ public static final int SECURITY_EAP_SUITE_B = 6;
private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1;
@@ -433,7 +436,7 @@
if (isConnectable()) {
builder.append(',').append("connectable");
}
- if (security != SECURITY_NONE) {
+ if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
builder.append(',').append(securityToString(security, pskType));
}
builder.append(",level=").append(getLevel());
@@ -720,6 +723,9 @@
case SECURITY_EAP:
return concise ? context.getString(R.string.wifi_security_short_eap) :
context.getString(R.string.wifi_security_eap);
+ case SECURITY_EAP_SUITE_B:
+ return concise ? context.getString(R.string.wifi_security_short_eap_suiteb) :
+ context.getString(R.string.wifi_security_eap_suiteb);
case SECURITY_PSK:
switch (pskType) {
case PSK_WPA:
@@ -739,6 +745,12 @@
case SECURITY_WEP:
return concise ? context.getString(R.string.wifi_security_short_wep) :
context.getString(R.string.wifi_security_wep);
+ case SECURITY_SAE:
+ return concise ? context.getString(R.string.wifi_security_short_sae) :
+ context.getString(R.string.wifi_security_sae);
+ case SECURITY_OWE:
+ return concise ? context.getString(R.string.wifi_security_short_owe) :
+ context.getString(R.string.wifi_security_owe);
case SECURITY_NONE:
default:
return concise ? "" : context.getString(R.string.wifi_security_none);
@@ -980,13 +992,20 @@
* Can only be called for unsecured networks.
*/
public void generateOpenNetworkConfig() {
- if (security != SECURITY_NONE)
+ if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
throw new IllegalStateException();
+ }
if (mConfig != null)
return;
mConfig = new WifiConfiguration();
mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
- mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+
+ if (security == SECURITY_NONE) {
+ mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+ } else {
+ mConfig.allowedKeyManagement.set(KeyMgmt.OWE);
+ mConfig.requirePMF = true;
+ }
}
public void saveWifiState(Bundle savedState) {
@@ -1288,22 +1307,38 @@
private static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
+ } else if (result.capabilities.contains("SAE")) {
+ return SECURITY_SAE;
} else if (result.capabilities.contains("PSK")) {
return SECURITY_PSK;
+ } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+ return SECURITY_EAP_SUITE_B;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
+ } else if (result.capabilities.contains("OWE")) {
+ return SECURITY_OWE;
}
+
return SECURITY_NONE;
}
static int getSecurity(WifiConfiguration config) {
+ if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
+ return SECURITY_SAE;
+ }
if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
return SECURITY_PSK;
}
+ if (config.allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ return SECURITY_EAP_SUITE_B;
+ }
if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return SECURITY_EAP;
}
+ if (config.allowedKeyManagement.get(KeyMgmt.OWE)) {
+ return SECURITY_OWE;
+ }
return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
}
@@ -1321,6 +1356,12 @@
return "PSK";
} else if (security == SECURITY_EAP) {
return "EAP";
+ } else if (security == SECURITY_SAE) {
+ return "SAE";
+ } else if (security == SECURITY_EAP_SUITE_B) {
+ return "SUITE_B";
+ } else if (security == SECURITY_OWE) {
+ return "OWE";
}
return "NONE";
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index f3c43cc..db364a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -200,7 +200,8 @@
if (frictionImageView == null || mFrictionSld == null) {
return;
}
- if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+ if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+ && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
mFrictionSld.setState(STATE_SECURED);
} else if (mAccessPoint.isMetered()) {
mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b46c288..ca0267c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1643,11 +1643,11 @@
Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
- SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_ENABLED);
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.NON_INTERACTIVE_UI_TIMEOUT_MS);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
- SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_MS);
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.INTERACTIVE_UI_TIMEOUT_MS);
p.end(accessibilityToken);
dumpSetting(s, p,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index b4fc820..887ea59 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -13,11 +13,11 @@
*/
package com.android.systemui.plugins;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
import android.graphics.Paint.Style;
import android.view.View;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
/**
* This plugin is used to replace main clock in keyguard.
*/
@@ -44,4 +44,9 @@
* @param color A color value.
*/
void setTextColor(int color);
+
+ /**
+ * Notifies that time tick alarm from doze service fired.
+ */
+ default void dozeTimeTick() { }
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
new file mode 100644
index 0000000..dce02e1
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
@@ -0,0 +1,39 @@
+/*
+ * 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.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Used to capture Falsing data (related to unlocking the screen).
+ *
+ * The intent is that the data can later be analyzed to validate the quality of the
+ * {@link com.android.systemui.classifier.FalsingManager}.
+ */
+@ProvidesInterface(action = FalsingPlugin.ACTION, version = FalsingPlugin.VERSION)
+public interface FalsingPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.FALSING_PLUGIN";
+ int VERSION = 1;
+
+ /**
+ * Called when there is data to be recorded.
+ *
+ * @param success Indicates whether the action is considered a success.
+ * @param data The raw data to be recorded for analysis.
+ */
+ void dataCollected(boolean success, byte[] data);
+}
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index d4dfdee..d041556 100644
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -21,6 +21,6 @@
<corners android:radius="1dp"
android:topLeftRadius="@dimen/biometric_dialog_corner_size"
android:topRightRadius="@dimen/biometric_dialog_corner_size"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"/>
+ android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
+ android:bottomRightRadius="@dimen/biometric_dialog_corner_size"/>
</shape>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index ec25e31..67c0adf 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -31,7 +31,8 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
<!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
on horizontal/portrait orientation -->
@@ -43,11 +44,13 @@
<LinearLayout
android:id="@+id/dialog"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:elevation="2dp"
- android:background="@drawable/biometric_dialog_bg">
+ android:background="@drawable/biometric_dialog_bg"
+ android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
+ android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
+ android:layout_marginRight="@dimen/biometric_dialog_border_padding">
<TextView
android:id="@+id/title"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 525421a..3050e79 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -889,6 +889,7 @@
<dimen name="biometric_dialog_biometric_icon_size">64dp</dimen>
<dimen name="biometric_dialog_corner_size">4dp</dimen>
<dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
+ <dimen name="biometric_dialog_border_padding">4dp</dimen>
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 013745a..8881f8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -143,6 +143,15 @@
}
/**
+ * Notifies that time tick alarm from doze service fired.
+ */
+ public void dozeTimeTick() {
+ if (mClockPlugin != null) {
+ mClockPlugin.dozeTimeTick();
+ }
+ }
+
+ /**
* When plugin changes, set all kept parameters into newer plugin.
*/
private void initPluginParams() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a403b75..f701e22 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -47,7 +47,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import com.google.android.collect.Sets;
@@ -276,6 +275,7 @@
public void dozeTimeTick() {
refreshTime();
mKeyguardSlice.refresh();
+ mClockView.dozeTimeTick();
}
private void refreshTime() {
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 4010c43..46e004c 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -35,6 +35,11 @@
import android.view.MotionEvent;
import android.widget.Toast;
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.FalsingPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -75,6 +80,8 @@
private static DataCollector sInstance = null;
+ private FalsingPlugin mFalsingPlugin = null;
+
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -82,6 +89,16 @@
}
};
+ private final PluginListener mPluginListener = new PluginListener<FalsingPlugin>() {
+ public void onPluginConnected(FalsingPlugin plugin, Context context) {
+ mFalsingPlugin = plugin;
+ }
+
+ public void onPluginDisconnected(FalsingPlugin plugin) {
+ mFalsingPlugin = null;
+ }
+ };
+
private DataCollector(Context context) {
mContext = context;
@@ -106,6 +123,8 @@
UserHandle.USER_ALL);
updateConfiguration();
+
+ Dependency.get(PluginManager.class).addPluginListener(mPluginListener, FalsingPlugin.class);
}
public static DataCollector getInstance(Context context) {
@@ -191,24 +210,28 @@
@Override
public void run() {
byte[] b = Session.toByteArray(currentSession.toProto());
- String dir = mContext.getFilesDir().getAbsolutePath();
- if (currentSession.getResult() != Session.SUCCESS) {
- if (!mDisableUnlocking && !mCollectBadTouches) {
- return;
+
+ if (mFalsingPlugin != null) {
+ mFalsingPlugin.dataCollected(currentSession.getResult() == Session.SUCCESS, b);
+ } else {
+ String dir = mContext.getFilesDir().getAbsolutePath();
+ if (currentSession.getResult() != Session.SUCCESS) {
+ if (!mDisableUnlocking && !mCollectBadTouches) {
+ return;
+ }
+ dir += "/bad_touches";
+ } else if (!mDisableUnlocking) {
+ dir += "/good_touches";
}
- dir += "/bad_touches";
- } else if (!mDisableUnlocking) {
- dir += "/good_touches";
- }
- File file = new File(dir);
- file.mkdir();
- File touch = new File(file, "trace_" + System.currentTimeMillis());
-
- try {
- new FileOutputStream(touch).write(b);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ File file = new File(dir);
+ file.mkdir();
+ File touch = new File(file, "trace_" + System.currentTimeMillis());
+ try {
+ new FileOutputStream(touch).write(b);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 7935115..1faae9d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -42,6 +42,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
/**
* Abstract base class. Shows a dialog for BiometricPrompt.
@@ -199,7 +200,10 @@
final Button negative = mLayout.findViewById(R.id.button2);
final Button positive = mLayout.findViewById(R.id.button1);
- mDialog.getLayoutParams().width = (int) mDialogWidth;
+ if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
+ mDialog.getLayoutParams().width = (int) mDialogWidth;
+ }
+
mLastState = STATE_NONE;
updateState(STATE_AUTHENTICATING);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 8994568..bc662e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
package com.android.systemui.statusbar;
import android.content.pm.UserInfo;
-import android.os.SystemProperties;
import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
@@ -26,8 +25,6 @@
String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
- boolean AUTO_DEMOTE_NOTIFICATIONS = SystemProperties.getBoolean("debug.demote_notifs", false);
-
boolean shouldAllowLockscreenRemoteInput();
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0108469..e3bc5b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -49,6 +49,7 @@
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -293,7 +294,7 @@
return false;
}
boolean exceedsPriorityThreshold;
- if (AUTO_DEMOTE_NOTIFICATIONS) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)) {
exceedsPriorityThreshold =
getEntryManager().getNotificationData().getImportance(sbn.getKey())
>= IMPORTANCE_DEFAULT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 92765bb..7581d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,7 +24,6 @@
import android.view.ViewGroup;
import com.android.systemui.Dependency;
-import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -380,6 +379,7 @@
}
row.showAppOpsIcons(entry.mActiveAppOps);
+ row.setAudiblyAlerted(entry.audiblyAlerted);
}
Trace.beginSection("NotificationPresenter#onUpdateRowStates");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 3539fff..b84b77c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -51,13 +51,14 @@
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -75,8 +76,6 @@
import java.util.List;
import java.util.Objects;
-import androidx.annotation.Nullable;
-
/**
* The list of currently displaying notifications.
*/
@@ -102,6 +101,7 @@
public String key;
public StatusBarNotification notification;
public NotificationChannel channel;
+ public boolean audiblyAlerted;
public StatusBarIconView icon;
public StatusBarIconView expandedIcon;
public ExpandableNotificationRow row; // the outer expanded view
@@ -154,6 +154,7 @@
public void populateFromRanking(@NonNull Ranking ranking) {
channel = ranking.getChannel();
+ audiblyAlerted = ranking.audiblyAlerted();
snoozeCriteria = ranking.getSnoozeCriteria();
userSentiment = ranking.getUserSentiment();
smartActions = ranking.getSmartActions() == null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 66ba9e9..1f48c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar.notification;
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
+
import android.content.Context;
import android.graphics.Color;
+import android.provider.Settings;
import android.view.View;
import android.widget.ImageView;
@@ -68,4 +71,10 @@
context.getResources().getDisplayMetrics().density);
return (int) (dimensionPixelSize * factor);
}
+
+ /** Returns the value of the new interruption model setting. */
+ public static boolean useNewInterruptionModel(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 0) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 965fb13..5166e06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,14 +16,22 @@
package com.android.systemui.statusbar.notification.row;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
-import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
+ .ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView
+ .VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .FLAG_CONTENT_VIEW_PUBLIC;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater
+ .InflationCallback;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1658,6 +1666,17 @@
mPublicLayout.showAppOpsIcons(activeOps);
}
+ /** Sets whether the notification being displayed audibly alerted the user. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)) {
+ if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+ mChildrenContainer.getHeaderView().setAudiblyAlerted(audiblyAlerted);
+ }
+ mPrivateLayout.setAudiblyAlerted(audiblyAlerted);
+ mPublicLayout.setAudiblyAlerted(audiblyAlerted);
+ }
+ }
+
public View.OnClickListener getAppOpsOnClickListener() {
return mOnAppOpsClickListener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 11cf8e0..fa3fa5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1551,6 +1551,19 @@
}
}
+ /** Sets whether the notification being displayed audibly alerted the user. */
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
+ mContractedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
+ mExpandedWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
+ mHeadsUpWrapper.getNotificationHeader().setAudiblyAlerted(audiblyAlerted);
+ }
+ }
+
public NotificationHeaderView getContractedNotificationHeader() {
if (mContractedChild != null) {
return mContractedWrapper.getNotificationHeader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 7e60c4b..674c8ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,17 +16,8 @@
package com.android.systemui.statusbar.notification.row;
-import java.util.ArrayList;
-
import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -45,6 +36,15 @@
import android.widget.FrameLayout.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
+import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+
+import java.util.ArrayList;
+import java.util.List;
public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
ExpandableNotificationRow.LayoutListener {
@@ -70,7 +70,8 @@
private MenuItem mInfoItem;
private MenuItem mAppOpsItem;
private MenuItem mSnoozeItem;
- private ArrayList<MenuItem> mMenuItems;
+ private ArrayList<MenuItem> mLeftMenuItems;
+ private ArrayList<MenuItem> mRightMenuItems;
private OnMenuEventListener mMenuListener;
private ValueAnimator mFadeAnimator;
@@ -107,12 +108,13 @@
mContext = context;
mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear);
mHandler = new Handler(Looper.getMainLooper());
- mMenuItems = new ArrayList<>();
+ mLeftMenuItems = new ArrayList<>();
+ mRightMenuItems = new ArrayList<>();
}
@Override
public ArrayList<MenuItem> getMenuItems(Context context) {
- return mMenuItems;
+ return mOnLeft ? mLeftMenuItems : mRightMenuItems;
}
@Override
@@ -231,7 +233,8 @@
final Resources res = mContext.getResources();
mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
- mMenuItems.clear();
+ mLeftMenuItems.clear();
+ mRightMenuItems.clear();
// Construct the menu items based on the notification
if (mParent != null && mParent.getStatusBarNotification() != null) {
int flags = mParent.getStatusBarNotification().getNotification().flags;
@@ -239,24 +242,19 @@
if (!isForeground) {
// Only show snooze for non-foreground notifications
mSnoozeItem = createSnoozeItem(mContext);
- mMenuItems.add(mSnoozeItem);
+ mLeftMenuItems.add(mSnoozeItem);
+ mRightMenuItems.add(mSnoozeItem);
}
}
mInfoItem = createInfoItem(mContext);
- mMenuItems.add(mInfoItem);
+ mLeftMenuItems.add(mInfoItem);
+ mRightMenuItems.add(mInfoItem);
mAppOpsItem = createAppOpsItem(mContext);
- mMenuItems.add(mAppOpsItem);
+ mLeftMenuItems.add(mAppOpsItem);
+ mRightMenuItems.add(mAppOpsItem);
- // Construct the menu views
- if (mMenuContainer != null) {
- mMenuContainer.removeAllViews();
- } else {
- mMenuContainer = new FrameLayout(mContext);
- }
- for (int i = 0; i < mMenuItems.size(); i++) {
- addMenuView(mMenuItems.get(i), mMenuContainer);
- }
+ populateMenuViews();
if (resetState) {
resetState(false /* notify */);
} else {
@@ -268,6 +266,18 @@
}
}
+ private void populateMenuViews() {
+ if (mMenuContainer != null) {
+ mMenuContainer.removeAllViews();
+ } else {
+ mMenuContainer = new FrameLayout(mContext);
+ }
+ List<MenuItem> menuItems = mOnLeft ? mLeftMenuItems : mRightMenuItems;
+ for (int i = 0; i < menuItems.size(); i++) {
+ addMenuView(menuItems.get(i), mMenuContainer);
+ }
+ }
+
private void resetState(boolean notify) {
setMenuAlpha(0f);
mIconsPlaced = false;
@@ -386,10 +396,16 @@
if (appName == null) {
return;
}
+ setAppName(appName, mLeftMenuItems);
+ setAppName(appName, mRightMenuItems);
+ }
+
+ private void setAppName(String appName,
+ ArrayList<MenuItem> menuItems) {
Resources res = mContext.getResources();
- final int count = mMenuItems.size();
+ final int count = menuItems.size();
for (int i = 0; i < count; i++) {
- MenuItem item = mMenuItems.get(i);
+ MenuItem item = menuItems.get(i);
String description = String.format(
res.getString(R.string.notification_menu_accessibility),
appName, item.getContentDescription());
@@ -402,7 +418,9 @@
@Override
public void onParentHeightUpdate() {
- if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
+ if (mParent == null
+ || (mLeftMenuItems.isEmpty() && mRightMenuItems.isEmpty())
+ || mMenuContainer == null) {
return;
}
int parentHeight = mParent.getActualHeight();
@@ -443,13 +461,14 @@
}
v.getLocationOnScreen(mIconLocation);
mParent.getLocationOnScreen(mParentLocation);
- final int centerX = (int) (mHorizSpaceForIcon / 2);
+ final int centerX = mHorizSpaceForIcon / 2;
final int centerY = v.getHeight() / 2;
final int x = mIconLocation[0] - mParentLocation[0] + centerX;
final int y = mIconLocation[1] - mParentLocation[1] + centerY;
final int index = mMenuContainer.indexOfChild(v);
if (mMenuListener != null) {
- mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ mMenuListener.onMenuClicked(mParent, x, y,
+ (mOnLeft ? mLeftMenuItems : mRightMenuItems).get(index));
}
}
@@ -469,6 +488,11 @@
// Do nothing
return;
}
+ boolean wasOnLeft = mOnLeft;
+ mOnLeft = showOnLeft;
+ if (wasOnLeft != showOnLeft) {
+ populateMenuViews();
+ }
final int count = mMenuContainer.getChildCount();
for (int i = 0; i < count; i++) {
final View v = mMenuContainer.getChildAt(i);
@@ -476,7 +500,6 @@
final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1));
v.setX(showOnLeft ? left : right);
}
- mOnLeft = showOnLeft;
mIconsPlaced = true;
}
@@ -603,6 +626,7 @@
private void addMenuView(MenuItem item, ViewGroup parent) {
View menuView = item.getMenuView();
if (menuView != null) {
+ menuView.setAlpha(mAlpha);
parent.addView(menuView);
menuView.setOnClickListener(this);
FrameLayout.LayoutParams lp = (LayoutParams) menuView.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f50e9a2..8e90f98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -20,7 +20,6 @@
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -50,7 +49,7 @@
public void onTuningChanged(String key, String newValue) {
if (key.equals(LOW_PRIORITY)) {
mShowLowPriority = "1".equals(newValue)
- || !NotificationLockscreenUserManager.AUTO_DEMOTE_NOTIFICATIONS;
+ || !NotificationUtils.useNewInterruptionModel(mContext);
if (mNotificationScrollLayout != null) {
updateStatusBarIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 3744105..9077b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -539,9 +539,9 @@
if (value != volumeItem.progress) {
volumeItem.listItem.setProgress(value);
volumeItem.progress = value;
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
- show(Events.SHOW_REASON_VOLUME_CHANGED);
- }
+ }
+ if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+ show(Events.SHOW_REASON_VOLUME_CHANGED);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index 459dc5d..0251f64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -437,21 +437,23 @@
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
- null, null);
+ false, null, null);
} else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
outRanking.getVisibilityOverride(), 255,
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), true, null, null);
+ outRanking.canShowBadge(), outRanking.getUserSentiment(), true, false, null,
+ null);
} else {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), false, null,
+ outRanking.canShowBadge(), outRanking.getUserSentiment(), false, false,
+ null,
null);
}
return true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index fb4ecd1..9c68e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -19,7 +19,6 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -168,7 +167,7 @@
0,
NotificationManager.IMPORTANCE_DEFAULT,
null, null,
- null, null, null, true, sentiment, false, null, null);
+ null, null, null, true, sentiment, false, false, null, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
}
@@ -186,7 +185,7 @@
NotificationManager.IMPORTANCE_DEFAULT,
null, null,
null, null, null, true,
- NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false,
+ NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, false,
smartActions, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index ddd0c2c..a947ea1 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2832,7 +2832,7 @@
// ACTION: Logs the end to end time taken by all provisioning tasks.
PROVISIONING_TOTAL_TASK_TIME_MS = 627;
- // OPEN: Settings > Privacy
+ // OPEN: Settings > Security
// CATEGORY: SETTINGS
// OS: O
ENTERPRISE_PRIVACY_SETTINGS = 628;
@@ -6579,6 +6579,11 @@
// OS: Q
BIOMETRIC_ENROLL_ACTIVITY = 1586;
+ // OPEN: Settings > Privacy
+ // CATEGORY: SETTINGS
+ // OS: Q
+ TOP_LEVEL_PRIVACY = 1587;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e89b951..5c189ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1672,22 +1672,23 @@
client -> client.setState(clientState)));
}
- private void scheduleNotifyClientsOfServicesStateChange(UserState userState) {
+ private void scheduleNotifyClientsOfServicesStateChangeLocked(UserState userState) {
+ updateRecommendedUiTimeoutLocked(userState);
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::sendServicesStateChanged,
- this, userState.mUserClients));
+ this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState)));
}
private void sendServicesStateChanged(
- RemoteCallbackList<IAccessibilityManagerClient> userClients) {
- notifyClientsOfServicesStateChange(mGlobalClients);
- notifyClientsOfServicesStateChange(userClients);
+ RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) {
+ notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout);
+ notifyClientsOfServicesStateChange(userClients, uiTimeout);
}
private void notifyClientsOfServicesStateChange(
- RemoteCallbackList<IAccessibilityManagerClient> clients) {
+ RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
clients.broadcast(ignoreRemoteException(
- client -> client.notifyServicesStateChanged()));
+ client -> client.notifyServicesStateChanged(uiTimeout)));
}
private void scheduleUpdateInputFilter(UserState userState) {
@@ -1701,24 +1702,6 @@
this, userState));
}
- private void scheduleSetAllClientsMinimumUiTimeout(UserState userState) {
- mMainHandler.sendMessage(obtainMessage(
- AccessibilityManagerService::sendMinimumUiTimeoutChanged,
- this, userState.mUserClients, userState.mMinimumUiTimeout));
- }
-
- private void sendMinimumUiTimeoutChanged(
- RemoteCallbackList<IAccessibilityManagerClient> userClients, int uiTimeout) {
- notifyClientsOfServicesMinimumUiTimeoutChange(mGlobalClients, uiTimeout);
- notifyClientsOfServicesMinimumUiTimeoutChange(userClients, uiTimeout);
- }
-
- private void notifyClientsOfServicesMinimumUiTimeoutChange(
- RemoteCallbackList<IAccessibilityManagerClient> clients, int uiTimeout) {
- clients.broadcast(ignoreRemoteException(
- client -> client.setMinimumUiTimeout(uiTimeout)));
- }
-
private void updateInputFilter(UserState userState) {
if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
@@ -1852,7 +1835,6 @@
scheduleUpdateClientsIfNeededLocked(userState);
updateRelevantEventsLocked(userState);
updateAccessibilityButtonTargetsLocked(userState);
- updateMinimumUiTimeoutLocked(userState);
}
private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -1971,7 +1953,7 @@
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
- somethingChanged |= readUserMinimumUiTimeoutSettingsLocked(userState);
+ somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
return somethingChanged;
}
@@ -2083,7 +2065,7 @@
}
userState.mServiceToEnableWithShortcut = componentNameToEnable;
- scheduleNotifyClientsOfServicesStateChange(userState);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
@@ -2118,17 +2100,20 @@
return true;
}
- private boolean readUserMinimumUiTimeoutSettingsLocked(UserState userState) {
- final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, 0,
- userState.mUserId) == 1;
- final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, 0,
+ private boolean readUserRecommendedUiTimeoutSettingsLocked(UserState userState) {
+ final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0,
userState.mUserId);
- if (enabled != userState.mUserMinimumUiTimeoutEnabled
- || timeout != userState.mUserMinimumUiTimeout) {
- userState.mUserMinimumUiTimeoutEnabled = enabled;
- userState.mUserMinimumUiTimeout = timeout;
+ final int interactiveUiTimeout = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0,
+ userState.mUserId);
+ if (nonInteractiveUiTimeout != userState.mUserNonInteractiveUiTimeout
+ || interactiveUiTimeout != userState.mUserInteractiveUiTimeout) {
+ userState.mUserNonInteractiveUiTimeout = nonInteractiveUiTimeout;
+ userState.mUserInteractiveUiTimeout = interactiveUiTimeout;
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
return true;
}
return false;
@@ -2300,25 +2285,33 @@
}
}
- private void updateMinimumUiTimeoutLocked(UserState userState) {
- int newUiTimeout = 0;
- if (userState.mUserMinimumUiTimeoutEnabled) {
- newUiTimeout = userState.mUserMinimumUiTimeout;
- } else {
+ private void updateRecommendedUiTimeoutLocked(UserState userState) {
+ int newNonInteractiveUiTimeout = userState.mUserNonInteractiveUiTimeout;
+ int newInteractiveUiTimeout = userState.mUserInteractiveUiTimeout;
+ // read from a11y services if user does not specify value
+ if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) {
+ int serviceNonInteractiveUiTimeout = 0;
+ int serviceInteractiveUiTimeout = 0;
final List<AccessibilityServiceConnection> services = userState.mBoundServices;
- final int numServices = services.size();
- for (int i = 0; i < numServices; i++) {
- final int serviceUiTimeout = services.get(i).getServiceInfo()
- .getMinimumUiTimeoutMillis();
- if (newUiTimeout < serviceUiTimeout) {
- newUiTimeout = serviceUiTimeout;
+ for (int i = 0; i < services.size(); i++) {
+ int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis();
+ if (serviceInteractiveUiTimeout < timeout) {
+ serviceInteractiveUiTimeout = timeout;
+ }
+ timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis();
+ if (serviceNonInteractiveUiTimeout < timeout) {
+ serviceNonInteractiveUiTimeout = timeout;
}
}
+ if (newNonInteractiveUiTimeout == 0) {
+ newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout;
+ }
+ if (newInteractiveUiTimeout == 0) {
+ newInteractiveUiTimeout = serviceInteractiveUiTimeout;
+ }
}
- if (newUiTimeout != userState.mMinimumUiTimeout) {
- userState.mMinimumUiTimeout = newUiTimeout;
- scheduleSetAllClientsMinimumUiTimeout(userState);
- }
+ userState.mNonInteractiveUiTimeout = newNonInteractiveUiTimeout;
+ userState.mInteractiveUiTimeout = newInteractiveUiTimeout;
}
@GuardedBy("mLock")
@@ -2473,19 +2466,24 @@
}
/**
- * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
- * on the screen for at least this long to give users time to react.
+ * Get the recommended timeout of interactive controls and non-interactive controls.
*
- * @return The minimum timeout for the current user in milliseconds.
+ * @return A long for pair of {@code int}s. First integer for interactive one, and second
+ * integer for non-interactive one.
*/
@Override
- public int getMinimumUiTimeout() {
+ public long getRecommendedTimeoutMillis() {
synchronized(mLock) {
final UserState userState = getCurrentUserStateLocked();
- return userState.mMinimumUiTimeout;
+ return getRecommendedTimeoutMillisLocked(userState);
}
}
+ private long getRecommendedTimeoutMillisLocked(UserState userState) {
+ return IntPair.of(userState.mInteractiveUiTimeout,
+ userState.mNonInteractiveUiTimeout);
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -2503,7 +2501,8 @@
pw.append(", navBarMagnificationEnabled="
+ userState.mIsNavBarMagnificationEnabled);
pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
- pw.append(", minimumUiTimeout=" + userState.mMinimumUiTimeout);
+ pw.append(", nonInteractiveUiTimeout=" + userState.mNonInteractiveUiTimeout);
+ pw.append(", interactiveUiTimeout=" + userState.mInteractiveUiTimeout);
if (mUiAutomationManager.isUiAutomationRunningLocked()) {
pw.append(", ");
mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
@@ -2819,7 +2818,7 @@
AccessibilityManagerService.UserState userState = getUserStateLocked(mCurrentUserId);
onUserStateChangedLocked(userState);
if (serviceInfoChanged) {
- scheduleNotifyClientsOfServicesStateChange(userState);
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
}
}
@@ -3794,7 +3793,8 @@
public ComponentName mServiceToEnableWithShortcut;
public int mLastSentClientState = -1;
- public int mMinimumUiTimeout = 0;
+ public int mNonInteractiveUiTimeout = 0;
+ public int mInteractiveUiTimeout = 0;
private int mSoftKeyboardShowMode = 0;
@@ -3809,8 +3809,8 @@
public boolean mIsPerformGesturesEnabled;
public boolean mIsFilterKeyEventsEnabled;
public boolean mAccessibilityFocusOnlyInActiveWindow;
- public boolean mUserMinimumUiTimeoutEnabled;
- public int mUserMinimumUiTimeout;
+ public int mUserNonInteractiveUiTimeout;
+ public int mUserInteractiveUiTimeout;
private boolean mBindInstantServiceAllowed;
@@ -3850,8 +3850,9 @@
// Clear event management state.
mLastSentClientState = -1;
- // clear minimum ui timeout
- mMinimumUiTimeout = 0;
+ // clear UI timeout
+ mNonInteractiveUiTimeout = 0;
+ mInteractiveUiTimeout = 0;
// Clear state persisted in settings.
mEnabledServices.clear();
@@ -3862,8 +3863,8 @@
mServiceAssignedToAccessibilityButton = null;
mIsNavBarMagnificationAssignedToAccessibilityButton = false;
mIsAutoclickEnabled = false;
- mUserMinimumUiTimeoutEnabled = false;
- mUserMinimumUiTimeout = 0;
+ mUserNonInteractiveUiTimeout = 0;
+ mUserInteractiveUiTimeout = 0;
}
public void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -3871,7 +3872,7 @@
serviceConnection.onAdded();
mBoundServices.add(serviceConnection);
mComponentNameToServiceMap.put(serviceConnection.mComponentName, serviceConnection);
- scheduleNotifyClientsOfServicesStateChange(this);
+ scheduleNotifyClientsOfServicesStateChangeLocked(this);
}
}
@@ -3897,7 +3898,7 @@
AccessibilityServiceConnection boundClient = mBoundServices.get(i);
mComponentNameToServiceMap.put(boundClient.mComponentName, boundClient);
}
- scheduleNotifyClientsOfServicesStateChange(this);
+ scheduleNotifyClientsOfServicesStateChangeLocked(this);
}
/**
@@ -4108,11 +4109,11 @@
private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
- private final Uri mUserMinimumUiTimeoutEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED);
+ private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
- private final Uri mUserMinimumUiTimeoutUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS);
+ private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
public AccessibilityContentObserver(Handler handler) {
super(handler);
@@ -4149,9 +4150,9 @@
contentResolver.registerContentObserver(
mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mUserMinimumUiTimeoutEnabledUri, false, this, UserHandle.USER_ALL);
+ mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mUserMinimumUiTimeoutUri, false, this, UserHandle.USER_ALL);
+ mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4202,11 +4203,9 @@
if (readAccessibilityButtonSettingsLocked(userState)) {
onUserStateChangedLocked(userState);
}
- } else if (mUserMinimumUiTimeoutEnabledUri.equals(uri)
- || mUserMinimumUiTimeoutUri.equals(uri)) {
- if (readUserMinimumUiTimeoutSettingsLocked(userState)) {
- updateMinimumUiTimeoutLocked(userState);
- }
+ } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
+ || mUserInteractiveUiTimeoutUri.equals(uri)) {
+ readUserRecommendedUiTimeoutSettingsLocked(userState);
}
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index cd98263..32667b8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1210,13 +1210,29 @@
@Override
public void setMode(int code, int uid, String packageName, int mode) {
+ setMode(code, uid, packageName, mode, true, false);
+ }
+
+ /**
+ * Sets the mode for a certain op and uid.
+ *
+ * @param code The op code to set
+ * @param uid The UID for which to set
+ * @param packageName The package for which to set
+ * @param mode The new mode to set
+ * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
+ * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
+ * false})
+ */
+ private void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean verifyUid, boolean isPrivileged) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, true);
+ Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -1575,7 +1591,7 @@
&& uidState.opModes.indexOfKey(code) >= 0) {
return uidState.opModes.get(code);
}
- Op op = getOpLocked(code, uid, resolvedPackageName, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, false, true, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -1918,7 +1934,7 @@
}
ClientState client = (ClientState) token;
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
if (op == null) {
return;
}
@@ -2172,6 +2188,43 @@
return ops;
}
+ /**
+ * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
+ *
+ * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
+ *
+ * @param uid The uid the of the package
+ * @param packageName The package name for which to get the state for
+ * @param edit Iff {@code true} create the {@link Ops} object if not yet created
+ * @param isPrivileged Whether the package is privileged or not
+ *
+ * @return The {@link Ops state} of all ops for the package
+ */
+ private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
+ boolean edit, boolean isPrivileged) {
+ UidState uidState = getUidStateLocked(uid, edit);
+ if (uidState == null) {
+ return null;
+ }
+
+ if (uidState.pkgOps == null) {
+ if (!edit) {
+ return null;
+ }
+ uidState.pkgOps = new ArrayMap<>();
+ }
+
+ Ops ops = uidState.pkgOps.get(packageName);
+ if (ops == null) {
+ if (!edit) {
+ return null;
+ }
+ ops = new Ops(packageName, uidState, isPrivileged);
+ uidState.pkgOps.put(packageName, ops);
+ }
+ return ops;
+ }
+
private void scheduleWriteLocked() {
if (!mWriteScheduled) {
mWriteScheduled = true;
@@ -2188,9 +2241,29 @@
}
}
- private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
- Ops ops = getOpsRawLocked(uid, packageName, edit,
- false /* uidMismatchExpected */);
+ /**
+ * Get the state of an op for a uid.
+ *
+ * @param code The code of the op
+ * @param uid The uid the of the package
+ * @param packageName The package name for which to get the state for
+ * @param edit Iff {@code true} create the {@link Op} object if not yet created
+ * @param verifyUid Iff {@code true} check that the package belongs to the uid
+ * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
+ * == false})
+ *
+ * @return The {@link Op state} of the op
+ */
+ private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
+ boolean verifyUid, boolean isPrivileged) {
+ Ops ops;
+
+ if (verifyUid) {
+ ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
+ } else {
+ ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+ }
+
if (ops == null) {
return null;
}
@@ -3948,5 +4021,11 @@
mProfileOwners = owners;
}
}
+
+ @Override
+ public void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean isPrivileged) {
+ AppOpsService.this.setMode(code, uid, packageName, mode, false, isPrivileged);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 924b075..f87a5f7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4756,6 +4756,10 @@
applyZenModeLocked(r);
mRankingHelper.sort(mNotificationList);
+ if (!r.isHidden()) {
+ buzzBeepBlinkLocked(r);
+ }
+
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(r, old);
@@ -4788,9 +4792,6 @@
+ n.getPackageName());
}
- if (!r.isHidden()) {
- buzzBeepBlinkLocked(r);
- }
maybeRecordInterruptionLocked(r);
} finally {
int N = mEnqueuedNotifications.size();
@@ -5157,6 +5158,7 @@
.setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
}
+ record.setAudiblyAlerted(buzz || beep);
}
@GuardedBy("mNotificationLock")
@@ -6561,6 +6563,7 @@
Bundle hidden = new Bundle();
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
+ Bundle audiblyAlerted = new Bundle();
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
if (!isVisibleToListener(record.sbn, info)) {
@@ -6590,6 +6593,7 @@
hidden.putBoolean(key, record.isHidden());
smartActions.putParcelableArrayList(key, record.getSmartActions());
smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
+ audiblyAlerted.putBoolean(key, record.getAudiblyAlerted());
}
final int M = keys.size();
String[] keysAr = keys.toArray(new String[M]);
@@ -6601,7 +6605,7 @@
return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
- smartActions, smartReplies);
+ smartActions, smartReplies, audiblyAlerted);
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e9f2718..84d0c01 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -170,6 +170,7 @@
private final NotificationStats mStats;
private int mUserSentiment;
private boolean mIsInterruptive;
+ private boolean mAudiblyAlerted;
private boolean mTextChanged;
private boolean mRecordedInterruption;
private int mNumberOfSmartRepliesAdded;
@@ -1023,6 +1024,10 @@
}
}
+ public void setAudiblyAlerted(boolean audiblyAlerted) {
+ mAudiblyAlerted = audiblyAlerted;
+ }
+
public void setTextChanged(boolean textChanged) {
mTextChanged = textChanged;
}
@@ -1039,6 +1044,11 @@
return mIsInterruptive;
}
+ /** Returns true if the notification audibly alerted the user. */
+ public boolean getAudiblyAlerted() {
+ return mAudiblyAlerted;
+ }
+
protected void setPeopleOverride(ArrayList<String> people) {
mPeopleOverride = people;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6ccd040..1a5b86c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -107,7 +107,9 @@
import java.util.Objects;
import java.util.Random;
-public class PackageInstallerService extends IPackageInstaller.Stub {
+/** The service responsible for installing packages. */
+public class PackageInstallerService extends IPackageInstaller.Stub implements
+ PackageSessionProvider {
private static final String TAG = "PackageInstaller";
private static final boolean LOGD = false;
@@ -296,6 +298,7 @@
in.setInput(fis, StandardCharsets.UTF_8.name());
int type;
+ PackageInstallerSession currentSession = null;
while ((type = in.next()) != END_DOCUMENT) {
if (type == START_TAG) {
final String tag = in.getName();
@@ -303,8 +306,10 @@
final PackageInstallerSession session;
try {
session = PackageInstallerSession.readFromXml(in, mInternalCallback,
- mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
+ mContext, mPm, mInstallThread.getLooper(), mSessionsDir, this);
+ currentSession = session;
} catch (Exception e) {
+ currentSession = null;
Slog.e(TAG, "Could not read session", e);
continue;
}
@@ -329,6 +334,10 @@
addHistoricalSessionLocked(session);
}
mAllocatedSessions.put(session.sessionId, true);
+ } else if (currentSession != null
+ && PackageInstallerSession.TAG_CHILD_SESSION.equals(tag)) {
+ currentSession.addChildSessionIdInternal(
+ PackageInstallerSession.readChildSessionIdFromXml(in));
}
}
}
@@ -436,70 +445,72 @@
}
}
- // Only system components can circumvent runtime permissions when installing.
- if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
- && mContext.checkCallingOrSelfPermission(Manifest.permission
- .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException("You need the "
- + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
- + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
- }
-
- if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
- || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- throw new IllegalArgumentException(
- "New installs into ASEC containers no longer supported");
- }
-
- // Defensively resize giant app icons
- if (params.appIcon != null) {
- final ActivityManager am = (ActivityManager) mContext.getSystemService(
- Context.ACTIVITY_SERVICE);
- final int iconSize = am.getLauncherLargeIconSize();
- if ((params.appIcon.getWidth() > iconSize * 2)
- || (params.appIcon.getHeight() > iconSize * 2)) {
- params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
- true);
- }
- }
-
- switch (params.mode) {
- case SessionParams.MODE_FULL_INSTALL:
- case SessionParams.MODE_INHERIT_EXISTING:
- break;
- default:
- throw new IllegalArgumentException("Invalid install mode: " + params.mode);
- }
-
- // If caller requested explicit location, sanity check it, otherwise
- // resolve the best internal or adopted location.
- if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- if (!PackageHelper.fitsOnInternal(mContext, params)) {
- throw new IOException("No suitable internal storage available");
+ if (!params.isMultiPackage) {
+ // Only system components can circumvent runtime permissions when installing.
+ if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
+ && mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException("You need the "
+ + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
- } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- if (!PackageHelper.fitsOnExternal(mContext, params)) {
- throw new IOException("No suitable external storage available");
+ if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+ || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ throw new IllegalArgumentException(
+ "New installs into ASEC containers no longer supported");
}
- } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
- // For now, installs to adopted media are treated as internal from
- // an install flag point-of-view.
- params.setInstallFlagsInternal();
+ // Defensively resize giant app icons
+ if (params.appIcon != null) {
+ final ActivityManager am = (ActivityManager) mContext.getSystemService(
+ Context.ACTIVITY_SERVICE);
+ final int iconSize = am.getLauncherLargeIconSize();
+ if ((params.appIcon.getWidth() > iconSize * 2)
+ || (params.appIcon.getHeight() > iconSize * 2)) {
+ params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
+ true);
+ }
+ }
- } else {
- // For now, installs to adopted media are treated as internal from
- // an install flag point-of-view.
- params.setInstallFlagsInternal();
+ switch (params.mode) {
+ case SessionParams.MODE_FULL_INSTALL:
+ case SessionParams.MODE_INHERIT_EXISTING:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid install mode: " + params.mode);
+ }
- // Resolve best location for install, based on combination of
- // requested install flags, delta size, and manifest settings.
- final long ident = Binder.clearCallingIdentity();
- try {
- params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ // If caller requested explicit location, sanity check it, otherwise
+ // resolve the best internal or adopted location.
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ if (!PackageHelper.fitsOnInternal(mContext, params)) {
+ throw new IOException("No suitable internal storage available");
+ }
+
+ } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ if (!PackageHelper.fitsOnExternal(mContext, params)) {
+ throw new IOException("No suitable external storage available");
+ }
+
+ } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
+ // For now, installs to adopted media are treated as internal from
+ // an install flag point-of-view.
+ params.setInstallFlagsInternal();
+
+ } else {
+ // For now, installs to adopted media are treated as internal from
+ // an install flag point-of-view.
+ params.setInstallFlagsInternal();
+
+ // Resolve best location for install, based on combination of
+ // requested install flags, delta size, and manifest settings.
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -525,17 +536,19 @@
// We're staging to exactly one location
File stageDir = null;
String stageCid = null;
- if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- final boolean isInstant =
- (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
- } else {
- stageCid = buildExternalStageCid(sessionId);
+ if (!params.isMultiPackage) {
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ final boolean isInstant =
+ (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
+ } else {
+ stageCid = buildExternalStageCid(sessionId);
+ }
}
-
- session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
- mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
- params, createdMillis, stageDir, stageCid, false, false);
+ session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
+ mInstallThread.getLooper(), sessionId, userId, installerPackageName,
+ callingUid, params, createdMillis, stageDir, stageCid, false, false, null,
+ SessionInfo.INVALID_ID);
synchronized (mSessions) {
mSessions.put(sessionId, session);
@@ -678,7 +691,7 @@
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.userId == userId) {
+ if (session.userId == userId && !session.hasParentSessionId()) {
result.add(session.generateInfo(false));
}
}
@@ -699,7 +712,7 @@
SessionInfo info = session.generateInfo(false);
if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
- && session.userId == userId) {
+ && session.userId == userId && !session.hasParentSessionId()) {
result.add(info);
}
}
@@ -781,6 +794,13 @@
mCallbacks.unregister(callback);
}
+ @Override
+ public PackageInstallerSession getSession(int sessionId) {
+ synchronized (mSessions) {
+ return mSessions.get(sessionId);
+ }
+ }
+
private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
int installerUid) {
int count = 0;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 249edab..26f6e96 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -47,6 +47,8 @@
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
@@ -69,6 +71,7 @@
import android.os.FileBridge;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -90,6 +93,7 @@
import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
@@ -130,6 +134,7 @@
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
+ static final String TAG_CHILD_SESSION = "childSession";
private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
private static final String ATTR_SESSION_ID = "sessionId";
private static final String ATTR_USER_ID = "userId";
@@ -140,6 +145,8 @@
private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
private static final String ATTR_PREPARED = "prepared";
private static final String ATTR_SEALED = "sealed";
+ private static final String ATTR_MULTI_PACKAGE = "multiPackage";
+ private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
private static final String ATTR_MODE = "mode";
private static final String ATTR_INSTALL_FLAGS = "installFlags";
private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -157,6 +164,7 @@
private static final String ATTR_INSTALL_REASON = "installRason";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
+ private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -165,6 +173,7 @@
private final Context mContext;
private final PackageManagerService mPm;
private final Handler mHandler;
+ private final PackageSessionProvider mSessionProvider;
final int sessionId;
final int userId;
@@ -236,6 +245,10 @@
private long mVersionCode;
@GuardedBy("mLock")
private PackageParser.SigningDetails mSigningDetails;
+ @GuardedBy("mLock")
+ private SparseIntArray mChildSessionIds = new SparseIntArray();
+ @GuardedBy("mLock")
+ private int mParentSessionId;
/**
* Path to the validated base APK for this session, which may point at an
@@ -372,12 +385,16 @@
}
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
- Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
+ Context context, PackageManagerService pm,
+ PackageSessionProvider sessionProvider, Looper looper,
+ int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
- File stageDir, String stageCid, boolean prepared, boolean sealed) {
+ File stageDir, String stageCid, boolean prepared, boolean sealed,
+ @Nullable int[] childSessionIds, int parentSessionId) {
mCallback = callback;
mContext = context;
mPm = pm;
+ mSessionProvider = sessionProvider;
mHandler = new Handler(looper, mHandlerCallback);
this.sessionId = sessionId;
@@ -389,8 +406,14 @@
this.createdMillis = createdMillis;
this.stageDir = stageDir;
this.stageCid = stageCid;
+ if (childSessionIds != null) {
+ for (int childSessionId : childSessionIds) {
+ mChildSessionIds.put(childSessionId, 0);
+ }
+ }
+ this.mParentSessionId = parentSessionId;
- if ((stageDir == null) == (stageCid == null)) {
+ if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
throw new IllegalArgumentException(
"Exactly one of stageDir or stageCid stage must be set");
}
@@ -439,6 +462,12 @@
info.referrerUri = params.referrerUri;
info.grantedRuntimePermissions = params.grantedRuntimePermissions;
info.installFlags = params.installFlags;
+ info.isMultiPackage = params.isMultiPackage;
+ info.parentSessionId = mParentSessionId;
+ info.childSessionIds = mChildSessionIds.copyKeys();
+ if (info.childSessionIds == null) {
+ info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
+ }
}
return info;
}
@@ -762,6 +791,92 @@
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
+ if (!markAsCommitted(statusReceiver, forTransfer /* enforce */)) {
+ return;
+ }
+ if (isMultiPackage()) {
+
+ final SparseIntArray remainingSessions = mChildSessionIds.clone();
+ final ChildStatusIntentReceiver localIntentReceiver =
+ new ChildStatusIntentReceiver(remainingSessions, statusReceiver);
+ for (int childSessionId : getChildSessionIds()) {
+ mSessionProvider.getSession(childSessionId)
+ .markAsCommitted(localIntentReceiver.getIntentSender(), forTransfer);
+ }
+ }
+ mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
+ }
+
+ private class ChildStatusIntentReceiver {
+ private final SparseIntArray mChildSessionsRemaining;
+ private final IntentSender mStatusReceiver;
+ private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+ statusUpdate(intent);
+ }
+ };
+
+ private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
+ IntentSender statusReceiver) {
+ this.mChildSessionsRemaining = remainingSessions;
+ this.mStatusReceiver = statusReceiver;
+ }
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public void statusUpdate(Intent intent) {
+ mHandler.post(() -> {
+ if (mChildSessionsRemaining.size() == 0) {
+ return;
+ }
+ final int sessionId = intent.getIntExtra(
+ PackageInstaller.EXTRA_SESSION_ID, 0);
+ final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+ if (PackageInstaller.STATUS_SUCCESS == status) {
+ mChildSessionsRemaining.removeAt(sessionIndex);
+ if (mChildSessionsRemaining.size() == 0) {
+ try {
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+ PackageInstallerSession.this.sessionId);
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ }
+ } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
+ try {
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ } else {
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+ PackageInstallerSession.this.sessionId);
+ mChildSessionsRemaining.clear(); // we're done. Don't send any more.
+ try {
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ }
+ });
+ }
+ }
+
+
+ /**
+ * Do everything but actually commit the session. If this was not already called, the session
+ * will be sealed and marked as committed. The caller of this method is responsible for
+ * subsequently submitting this session for processing.
+ *
+ * This method may be called multiple times to update the status receiver validate caller
+ * permissions.
+ */
+ public boolean markAsCommitted(
+ @NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
@@ -786,6 +901,12 @@
}
}
+ // After validations and updating the observer, we can skip re-sealing, etc. because we
+ // have already marked ourselves as committed.
+ if (mCommitted) {
+ return true;
+ }
+
wasSealed = mSealed;
if (!mSealed) {
try {
@@ -796,7 +917,7 @@
// Do now throw an exception here to stay compatible with O and older
destroyInternal();
dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
- return;
+ return false;
}
}
@@ -809,7 +930,6 @@
mActiveCount.incrementAndGet();
mCommitted = true;
- mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
if (!wasSealed) {
@@ -818,6 +938,7 @@
// the session lock, since otherwise it's a lock inversion.
mCallback.onSessionSealedBlocking(this);
}
+ return true;
}
/**
@@ -833,32 +954,37 @@
assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
- final PackageInfo pkgInfo = mPm.getPackageInfo(
- params.appPackageName, PackageManager.GET_SIGNATURES
- | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
-
- resolveStageDirLocked();
-
mSealed = true;
- try {
- if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
- validateApexInstallLocked(pkgInfo);
- } else {
- // Verify that stage looks sane with respect to existing application.
- // This currently only ensures packageName, versionCode, and certificate
- // consistency.
- validateApkInstallLocked(pkgInfo);
- }
- } catch (PackageManagerException e) {
- throw e;
- } catch (Throwable e) {
- // Convert all exceptions into package manager exceptions as only those are handled
- // in the code above
- throw new PackageManagerException(e);
- }
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information.
+ if (!params.isMultiPackage) {
+ final PackageInfo pkgInfo = mPm.getPackageInfo(
+ params.appPackageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
+
+ resolveStageDirLocked();
+
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ try {
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ validateApexInstallLocked(pkgInfo);
+ } else {
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ validateApkInstallLocked(pkgInfo);
+ }
+ } catch (PackageManagerException e) {
+ throw e;
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above
+ throw new PackageManagerException(e);
+ }
+ }
}
@Override
@@ -916,25 +1042,52 @@
@GuardedBy("mLock")
private void commitLocked()
throws PackageManagerException {
- if (mRelinquished) {
- Slog.d(TAG, "Ignoring commit after previous commit relinquished control");
+ final PackageManagerService.ActiveInstallSession committingSession =
+ makeSessionActiveLocked();
+ if (committingSession == null) {
return;
}
- if (mDestroyed) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
- }
- if (!mSealed) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
- }
-
- Preconditions.checkNotNull(mPackageName);
- Preconditions.checkNotNull(mSigningDetails);
- Preconditions.checkNotNull(mResolvedBaseFile);
-
- if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
- commitApexLocked();
+ if (isMultiPackage()) {
+ final int[] childSessionIds = getChildSessionIds();
+ List<PackageManagerService.ActiveInstallSession> childSessions =
+ new ArrayList<>(childSessionIds.length);
+ boolean success = true;
+ PackageManagerException failure = null;
+ for (int childSessionId : getChildSessionIds()) {
+ final PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
+ try {
+ final PackageManagerService.ActiveInstallSession activeSession =
+ session.makeSessionActiveLocked();
+ if (activeSession != null) {
+ if ((activeSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_APEX) != 0) {
+ // TODO(b/118865310): Add exception to this case for staged installs
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ "Atomic install is not supported for APEX packages.");
+ }
+ childSessions.add(activeSession);
+ }
+ } catch (PackageManagerException e) {
+ failure = e;
+ success = false;
+ }
+ }
+ if (!success) {
+ try {
+ mRemoteObserver.onPackageInstalled(
+ null, failure.error, failure.getLocalizedMessage(), null);
+ } catch (RemoteException ignored) {
+ }
+ return;
+ }
+ mPm.installStage(childSessions);
} else {
- commitApkLocked();
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ commitApexLocked();
+ } else {
+ mPm.installStage(committingSession);
+ }
}
}
@@ -954,81 +1107,105 @@
}
}
+ /**
+ * Stages this session for install and returns a
+ * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
+ * in case permissions need to be requested before install can proceed.
+ */
@GuardedBy("mLock")
- private void commitApkLocked() throws PackageManagerException {
- if (needToAskForPermissionsLocked()) {
- // User needs to confirm installation; give installer an intent they can use to involve
- // user.
- final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
- intent.setPackage(mPm.getPackageInstallerPackageName());
- intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
- try {
- mRemoteObserver.onUserActionRequired(intent);
- } catch (RemoteException ignored) {
- }
-
- // Commit was keeping session marked as active until now; release
- // that extra refcount so session appears idle.
- closeInternal(false);
- return;
+ private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
+ throws PackageManagerException {
+ if (mRelinquished) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session relinquished");
+ }
+ if (mDestroyed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
+ }
+ if (!mSealed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
- // Inherit any packages and native libraries from existing install that
- // haven't been overridden.
- if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
- try {
- final List<File> fromFiles = mResolvedInheritedFiles;
- final File toDir = resolveStageDirLocked();
+ if (!params.isMultiPackage) {
+ Preconditions.checkNotNull(mPackageName);
+ Preconditions.checkNotNull(mSigningDetails);
+ Preconditions.checkNotNull(mResolvedBaseFile);
- if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
- if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
- throw new IllegalStateException("mInheritedFilesBase == null");
+ if (needToAskForPermissionsLocked()) {
+ // User needs to confirm installation;
+ // give installer an intent they can use to involve
+ // user.
+ final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
+ intent.setPackage(mPm.getPackageInstallerPackageName());
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ try {
+ mRemoteObserver.onUserActionRequired(intent);
+ } catch (RemoteException ignored) {
}
- if (isLinkPossible(fromFiles, toDir)) {
- if (!mResolvedInstructionSets.isEmpty()) {
- final File oatDir = new File(toDir, "oat");
- createOatDirs(mResolvedInstructionSets, oatDir);
+ // Commit was keeping session marked as active until now; release
+ // that extra refcount so session appears idle.
+ closeInternal(false);
+ return null;
+ }
+
+ // Inherit any packages and native libraries from existing install that
+ // haven't been overridden.
+ if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+ try {
+ final List<File> fromFiles = mResolvedInheritedFiles;
+ final File toDir = resolveStageDirLocked();
+
+ if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
+ if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
+ throw new IllegalStateException("mInheritedFilesBase == null");
}
- // pre-create lib dirs for linking if necessary
- if (!mResolvedNativeLibPaths.isEmpty()) {
- for (String libPath : mResolvedNativeLibPaths) {
- // "/lib/arm64" -> ["lib", "arm64"]
- final int splitIndex = libPath.lastIndexOf('/');
- if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
- Slog.e(TAG, "Skipping native library creation for linking due to "
- + "invalid path: " + libPath);
- continue;
- }
- final String libDirPath = libPath.substring(1, splitIndex);
- final File libDir = new File(toDir, libDirPath);
- if (!libDir.exists()) {
- NativeLibraryHelper.createNativeLibrarySubdir(libDir);
- }
- final String archDirPath = libPath.substring(splitIndex + 1);
- NativeLibraryHelper.createNativeLibrarySubdir(
- new File(libDir, archDirPath));
+
+ if (isLinkPossible(fromFiles, toDir)) {
+ if (!mResolvedInstructionSets.isEmpty()) {
+ final File oatDir = new File(toDir, "oat");
+ createOatDirs(mResolvedInstructionSets, oatDir);
}
+ // pre-create lib dirs for linking if necessary
+ if (!mResolvedNativeLibPaths.isEmpty()) {
+ for (String libPath : mResolvedNativeLibPaths) {
+ // "/lib/arm64" -> ["lib", "arm64"]
+ final int splitIndex = libPath.lastIndexOf('/');
+ if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
+ Slog.e(TAG,
+ "Skipping native library creation for linking due to "
+ + "invalid path: " + libPath);
+ continue;
+ }
+ final String libDirPath = libPath.substring(1, splitIndex);
+ final File libDir = new File(toDir, libDirPath);
+ if (!libDir.exists()) {
+ NativeLibraryHelper.createNativeLibrarySubdir(libDir);
+ }
+ final String archDirPath = libPath.substring(splitIndex + 1);
+ NativeLibraryHelper.createNativeLibrarySubdir(
+ new File(libDir, archDirPath));
+ }
+ }
+ linkFiles(fromFiles, toDir, mInheritedFilesBase);
+ } else {
+ // TODO: this should delegate to DCS so the system process
+ // avoids holding open FDs into containers.
+ copyFiles(fromFiles, toDir);
}
- linkFiles(fromFiles, toDir, mInheritedFilesBase);
- } else {
- // TODO: this should delegate to DCS so the system process
- // avoids holding open FDs into containers.
- copyFiles(fromFiles, toDir);
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Failed to inherit existing install", e);
}
- } catch (IOException e) {
- throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Failed to inherit existing install", e);
}
+
+ // TODO: surface more granular state from dexopt
+ mInternalProgress = 0.5f;
+ computeProgressLocked(true);
+
+ // Unpack native libraries
+ extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
}
-
- // TODO: surface more granular state from dexopt
- mInternalProgress = 0.5f;
- computeProgressLocked(true);
-
- // Unpack native libraries
- extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
-
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@@ -1053,8 +1230,11 @@
}
mRelinquished = true;
- mPm.installStage(mPackageName, stageDir, localObserver, params,
- mInstallerPackageName, mInstallerUid, user, mSigningDetails);
+ final PackageManagerService.ActiveInstallSession activeInstallSession =
+ new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
+ localObserver, params, mInstallerPackageName, mInstallerUid, user,
+ mSigningDetails);
+ return activeInstallSession;
}
private static void maybeRenameFile(File from, File to) throws PackageManagerException {
@@ -1556,6 +1736,14 @@
}
}
+ /**
+ * Adds a child session ID without any safety / sanity checks. This should only be used to
+ * build a session from XML or similar.
+ */
+ void addChildSessionIdInternal(int sessionId) {
+ mChildSessionIds.put(sessionId, 0);
+ }
+
public void open() throws IOException {
if (mActiveCount.getAndIncrement() == 0) {
mCallback.onSessionActiveChanged(this, true);
@@ -1567,6 +1755,8 @@
if (!mPrepared) {
if (stageDir != null) {
prepareStageDir(stageDir);
+ } else if (params.isMultiPackage) {
+ // it's all ok
} else {
throw new IllegalArgumentException("stageDir must be set");
}
@@ -1615,6 +1805,81 @@
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
}
+ @Override
+ public boolean isMultiPackage() {
+ return params.isMultiPackage;
+ }
+
+ @Override
+ public int[] getChildSessionIds() {
+ final int[] childSessionIds = mChildSessionIds.copyKeys();
+ if (childSessionIds != null) {
+ return childSessionIds;
+ }
+ return EMPTY_CHILD_SESSION_ARRAY;
+ }
+
+ @Override
+ public void addChildSessionId(int sessionId) {
+ final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+ if (session == null) {
+ throw new RemoteException("Unable to add child.",
+ new PackageManagerException("Child session " + sessionId + " does not exist"),
+ false, true).rethrowAsRuntimeException();
+ }
+ synchronized (mLock) {
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (indexOfSession >= 0) {
+ return;
+ }
+ session.setParentSessionId(this.sessionId);
+ addChildSessionIdInternal(sessionId);
+ }
+ }
+
+ @Override
+ public void removeChildSessionId(int sessionId) {
+ final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+ synchronized (mLock) {
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (session != null) {
+ session.setParentSessionId(SessionInfo.INVALID_ID);
+ }
+ if (indexOfSession < 0) {
+ // not added in the first place; no-op
+ return;
+ }
+ mChildSessionIds.removeAt(indexOfSession);
+ }
+ }
+
+ /**
+ * Sets the parent session ID if not already set.
+ * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
+ */
+ void setParentSessionId(int parentSessionId) {
+ synchronized (mLock) {
+ if (parentSessionId != SessionInfo.INVALID_ID
+ && mParentSessionId != SessionInfo.INVALID_ID) {
+ throw new RemoteException("Unable to set parent session.",
+ new PackageManagerException(
+ "The parent of " + sessionId + " is" + " already set to "
+ + mParentSessionId), false,
+ true).rethrowAsRuntimeException();
+ }
+ this.mParentSessionId = parentSessionId;
+ }
+ }
+
+ boolean hasParentSessionId() {
+ return mParentSessionId != SessionInfo.INVALID_ID;
+ }
+
+ @Override
+ public int getParentSessionId() {
+ return mParentSessionId;
+ }
+
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
final IPackageInstallObserver2 observer;
final String packageName;
@@ -1704,6 +1969,7 @@
pw.printPair("mBridges", mBridges.size());
pw.printPair("mFinalStatus", mFinalStatus);
pw.printPair("mFinalMessage", mFinalMessage);
+ pw.printPair("params.isMultiPackage", params.isMultiPackage);
pw.println();
pw.decreaseIndent();
@@ -1754,6 +2020,10 @@
writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
writeBooleanAttribute(out, ATTR_SEALED, isSealed());
+ writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
+ // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
+ // we've read all sessions.
+ writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
writeIntAttribute(out, ATTR_MODE, params.mode);
writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
@@ -1788,6 +2058,12 @@
params.appIconLastModified = appIconFile.lastModified();
}
+ final int[] childSessionIds = getChildSessionIds();
+ for (int childSessionId : childSessionIds) {
+ out.startTag(null, TAG_CHILD_SESSION);
+ writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
+ out.endTag(null, TAG_CHILD_SESSION);
+ }
}
out.endTag(null, TAG_SESSION);
@@ -1832,11 +2108,15 @@
* @param installerThread Thread to be used for callbacks of this session
* @param sessionsDir The directory the sessions are stored in
*
+ * @param sessionProvider
* @return The newly created session
*/
+ // TODO(patb,109941548): modify readFromXml to consume to the next tag session tag so we
+ // can have a complete session for the constructor
public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
@NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
- @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
+ @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir,
+ @NonNull PackageSessionProvider sessionProvider)
throws IOException, XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
final int userId = readIntAttribute(in, ATTR_USER_ID);
@@ -1849,9 +2129,12 @@
final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
+ final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
+ SessionInfo.INVALID_ID);
final SessionParams params = new SessionParams(
SessionParams.MODE_INVALID);
+ params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
params.mode = readIntAttribute(in, ATTR_MODE);
params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
@@ -1874,9 +2157,16 @@
params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
params.appIconLastModified = appIconFile.lastModified();
}
-
- return new PackageInstallerSession(callback, context, pm,
+ return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, sessionId, userId, installerPackageName, installerUid,
- params, createdMillis, stageDir, stageCid, prepared, sealed);
+ params, createdMillis, stageDir, stageCid, prepared, sealed,
+ EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+ }
+
+ /**
+ * Reads the session ID from a child session tag stored in the provided {@link XmlPullParser}
+ */
+ static int readChildSessionIdFromXml(@NonNull XmlPullParser in) {
+ return readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ed3e857..ed5b33b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,6 +60,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -239,7 +240,6 @@
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
-import android.permission.PermissionManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
@@ -2930,60 +2930,6 @@
checkDefaultBrowser();
- // If a granted permission is split, all new permissions should be granted too
- if (mIsUpgrade) {
- final int callingUid = getCallingUid();
-
- final List<PermissionManager.SplitPermissionInfo> splitPermissions =
- mContext.getSystemService(PermissionManager.class).getSplitPermissions();
- final int numSplitPerms = splitPermissions.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- final PermissionManager.SplitPermissionInfo splitPerm =
- splitPermissions.get(splitPermNum);
- final String rootPerm = splitPerm.getSplitPermission();
-
- if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
- continue;
- }
-
- final int numPackages = mPackages.size();
- for (int packageNum = 0; packageNum < numPackages; packageNum++) {
- final PackageParser.Package pkg = mPackages.valueAt(packageNum);
-
- if (pkg.applicationInfo.targetSdkVersion >= splitPerm.getTargetSdk()
- || !pkg.requestedPermissions.contains(rootPerm)) {
- continue;
- }
-
- final int userId = UserHandle.getUserId(pkg.applicationInfo.uid);
- final String pkgName = pkg.packageName;
-
- if (checkPermission(rootPerm, pkgName, userId) == PERMISSION_DENIED) {
- continue;
- }
-
- final List<String> newPerms = splitPerm.getNewPermissions();
-
- final int numNewPerms = newPerms.size();
- for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
- final String newPerm = newPerms.get(newPermNum);
- if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
- continue;
- }
-
- if (DEBUG_PERMISSIONS) {
- Slog.v(TAG, "Granting " + newPerm + " to " + pkgName
- + " as the root permission " + rootPerm
- + " is already granted");
- }
-
- mPermissionManager.grantRuntimePermission(newPerm, pkgName, true,
- callingUid, userId, null);
- }
- }
- }
- }
-
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
@@ -12357,28 +12303,15 @@
return installReason;
}
- void installStage(String packageName, File stagedDir,
- IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
- String installerPackageName, int installerUid, UserHandle user,
- PackageParser.SigningDetails signingDetails) {
+ void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
- if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + packageName);
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
- final VerificationInfo verificationInfo = new VerificationInfo(
- sessionParams.originatingUri, sessionParams.referrerUri,
- sessionParams.originatingUid, installerUid);
-
- final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
-
final Message msg = mHandler.obtainMessage(INIT_COPY);
- final int installReason = fixUpInstallReason(installerPackageName, installerUid,
- sessionParams.installReason);
- final InstallParams params = new InstallParams(origin, null, observer,
- sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
- verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, signingDetails, installReason);
+ final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12390,6 +12323,22 @@
mHandler.sendMessage(msg);
}
+ void installStage(List<ActiveInstallSession> children)
+ throws PackageManagerException {
+ final Message msg = mHandler.obtainMessage(INIT_COPY);
+ final MultiPackageInstallParams params =
+ new MultiPackageInstallParams(UserHandle.ALL, children);
+ params.setTraceMethod("installStageMultiPackage")
+ .setTraceCookie(System.identityHashCode(params));
+ msg.obj = params;
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mHandler.sendMessage(msg);
+ }
+
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -13567,88 +13516,113 @@
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- // Result object to be returned
- PackageInstalledInfo res = new PackageInstalledInfo();
- res.setReturnCode(currentStatus);
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = null;
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- args.doPreInstall(res.returnCode);
- synchronized (mInstallLock) {
- installPackageTracedLI(args, res);
- }
- args.doPostInstall(res.returnCode, res.uid);
+ if (args.mMultiPackageInstallParams != null) {
+ args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
+ } else {
+ PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
+ processInstallRequestsAsync(
+ res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+ }
+ }
+
+ // Queue up an async operation since the package installation may take a little while.
+ private void processInstallRequestsAsync(boolean success,
+ List<InstallRequest> installRequests) {
+ mHandler.post(() -> {
+ if (success) {
+ for (InstallRequest request : installRequests) {
+ request.args.doPreInstall(request.installResult.returnCode);
}
-
- // A restore should be performed at this point if (a) the install
- // succeeded, (b) the operation is not an update, and (c) the new
- // package has not opted out of backup participation.
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
- final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
- boolean doRestore = !update
- && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
-
- // Set up the post-install work request bookkeeping. This will be used
- // and cleaned up by the post-install event handling regardless of whether
- // there's a restore pass performed. Token values are >= 1.
- int token;
- if (mNextInstallToken < 0) mNextInstallToken = 1;
- token = mNextInstallToken++;
-
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
- if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
- // Pass responsibility to the Backup Manager. It will perform a
- // restore if appropriate, then pass responsibility back to the
- // Package Manager to run the post-install observer callbacks
- // and broadcasts.
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (bm != null) {
- if (DEBUG_INSTALL) Log.v(TAG, "token " + token
- + " to BM for possible restore");
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- try {
- // TODO: http://b/22388012
- if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
- } else {
- doRestore = false;
- }
- } catch (RemoteException e) {
- // can't happen; the backup manager is local
- } catch (Exception e) {
- Slog.e(TAG, "Exception trying to enqueue restore", e);
- doRestore = false;
- }
- } else {
- Slog.e(TAG, "Backup Manager not found!");
- doRestore = false;
- }
+ synchronized (mInstallLock) {
+ installPackagesTracedLI(installRequests);
}
-
- if (!doRestore) {
- // No restore possible, or the Backup Manager was mysteriously not
- // available -- just fire the post-install work request directly.
- if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
-
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
- mHandler.sendMessage(msg);
+ for (InstallRequest request : installRequests) {
+ request.args.doPostInstall(
+ request.installResult.returnCode, request.installResult.uid);
}
}
+ for (InstallRequest request : installRequests) {
+ resolvePackageInstalledInfo(request.args,
+ request.installResult);
+ }
});
}
+ private PackageInstalledInfo createPackageInstalledInfo(
+ int currentStatus) {
+ PackageInstalledInfo res = new PackageInstalledInfo();
+ res.setReturnCode(currentStatus);
+ res.uid = -1;
+ res.pkg = null;
+ res.removedInfo = null;
+ return res;
+ }
+
+ private void resolvePackageInstalledInfo(InstallArgs args, PackageInstalledInfo res) {
+ // A restore should be performed at this point if (a) the install
+ // succeeded, (b) the operation is not an update, and (c) the new
+ // package has not opted out of backup participation.
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
+ final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+ boolean doRestore = !update
+ && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
+
+ // Set up the post-install work request bookkeeping. This will be used
+ // and cleaned up by the post-install event handling regardless of whether
+ // there's a restore pass performed. Token values are >= 1.
+ int token;
+ if (mNextInstallToken < 0) mNextInstallToken = 1;
+ token = mNextInstallToken++;
+
+ PostInstallData data = new PostInstallData(args, res);
+ mRunningInstalls.put(token, data);
+ if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+ // Pass responsibility to the Backup Manager. It will perform a
+ // restore if appropriate, then pass responsibility back to the
+ // Package Manager to run the post-install observer callbacks
+ // and broadcasts.
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "token " + token + " to BM for possible restore");
+ }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+ try {
+ // TODO: http://b/22388012
+ if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
+ bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+ } else {
+ doRestore = false;
+ }
+ } catch (RemoteException e) {
+ // can't happen; the backup manager is local
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception trying to enqueue restore", e);
+ doRestore = false;
+ }
+ } else {
+ Slog.e(TAG, "Backup Manager not found!");
+ doRestore = false;
+ }
+ }
+
+ if (!doRestore) {
+ // No restore possible, or the Backup Manager was mysteriously not
+ // available -- just fire the post-install work request directly.
+ if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+
+ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ mHandler.sendMessage(msg);
+ }
+ }
+
/**
* Callback from PackageSettings whenever an app is first transitioned out of the
* 'stopped' state. Normally we just issue the broadcast, but we can't do that if
@@ -13836,7 +13810,83 @@
}
}
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ class MultiPackageInstallParams extends HandlerParams {
+
+ private int mRet = INSTALL_SUCCEEDED;
+ @NonNull
+ private final ArrayList<InstallParams> mChildParams;
+ @NonNull
+ private final Map<InstallArgs, Integer> mVerifiedState;
+
+ MultiPackageInstallParams(
+ @NonNull UserHandle user,
+ @NonNull List<ActiveInstallSession> activeInstallSessions)
+ throws PackageManagerException {
+ super(user);
+ if (activeInstallSessions.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = new ArrayList<>(activeInstallSessions.size());
+ for (int i = 0; i < activeInstallSessions.size(); i++) {
+ final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
+ childParams.mParentInstallParams = this;
+ this.mChildParams.add(childParams);
+ }
+ this.mVerifiedState = new ArrayMap<>(mChildParams.size());
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (InstallParams params : mChildParams) {
+ params.handleStartCopy();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ break;
+ }
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (InstallParams params : mChildParams) {
+ params.handleReturnCode();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ break;
+ }
+ }
+ }
+
+ void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+ mVerifiedState.put(args, currentStatus);
+ boolean success = true;
+ if (mVerifiedState.size() != mChildParams.size()) {
+ return;
+ }
+ for (Integer status : mVerifiedState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ success = false;
+ break;
+ }
+ }
+ final List<InstallRequest> installRequests = new ArrayList<>(mVerifiedState.size());
+ for (Map.Entry<InstallArgs, Integer> entry : mVerifiedState.entrySet()) {
+ installRequests.add(new InstallRequest(entry.getKey(),
+ createPackageInstalledInfo(entry.getValue())));
+ }
+ processInstallRequestsAsync(success, installRequests);
+ }
+ }
+
class InstallParams extends HandlerParams {
+ // TODO: see if we can collapse this into ActiveInstallSession
+
final OriginInfo origin;
final MoveInfo move;
final IPackageInstallObserver2 observer;
@@ -13844,17 +13894,20 @@
final String installerPackageName;
final String volumeUuid;
private InstallArgs mArgs;
- private int mRet;
+ int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final VerificationInfo verificationInfo;
final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable
+ MultiPackageInstallParams mParentInstallParams;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
+ String[] grantedPermissions, PackageParser.SigningDetails signingDetails,
+ int installReason) {
super(user);
this.origin = origin;
this.move = move;
@@ -13869,6 +13922,34 @@
this.installReason = installReason;
}
+ InstallParams(ActiveInstallSession activeInstallSession) {
+ super(activeInstallSession.getUser());
+ if (DEBUG_INSTANT) {
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
+ }
+ }
+ verificationInfo = new VerificationInfo(
+ activeInstallSession.getSessionParams().originatingUri,
+ activeInstallSession.getSessionParams().referrerUri,
+ activeInstallSession.getSessionParams().originatingUid,
+ activeInstallSession.getInstallerUid());
+ origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+ move = null;
+ installReason = fixUpInstallReason(activeInstallSession.getInstallerPackageName(),
+ activeInstallSession.getInstallerUid(),
+ activeInstallSession.getSessionParams().installReason);
+ observer = activeInstallSession.getObserver();
+ installFlags = activeInstallSession.getSessionParams().installFlags;
+ installerPackageName = activeInstallSession.getInstallerPackageName();
+ volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
+ packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
+ grantedRuntimePermissions =
+ activeInstallSession.getSessionParams().grantedRuntimePermissions;
+ signingDetails = activeInstallSession.getSigningDetails();
+ }
+
@Override
public String toString() {
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
@@ -14290,6 +14371,7 @@
final int traceCookie;
final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable final MultiPackageInstallParams mMultiPackageInstallParams;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -14300,8 +14382,9 @@
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
- String traceMethod, int traceCookie, PackageParser.SigningDetails signingDetails,
- int installReason) {
+ String traceMethod, int traceCookie, SigningDetails signingDetails,
+ int installReason,
+ MultiPackageInstallParams multiPackageInstallParams) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -14316,6 +14399,7 @@
this.traceCookie = traceCookie;
this.signingDetails = signingDetails;
this.installReason = installReason;
+ this.mMultiPackageInstallParams = multiPackageInstallParams;
}
abstract int copyApk();
@@ -14411,7 +14495,7 @@
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason);
+ params.installReason, params.mParentInstallParams);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -14421,7 +14505,7 @@
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -14613,7 +14697,7 @@
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason);
+ params.installReason, params.mParentInstallParams);
}
int copyApk() {
@@ -15018,10 +15102,10 @@
}
@GuardedBy({"mInstallLock", "mPackages"})
- private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo installResult) {
+ private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
- installPackagesLI(Collections.singletonList(new InstallRequest(args, installResult)));
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+ installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -15361,7 +15445,7 @@
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.packageName
- + " in atomic install request.");
+ + " in multi-package install request.");
return;
}
}
@@ -23433,6 +23517,62 @@
return mProtectedPackages.isPackageStateProtected(userId, packageName);
}
+
+ static class ActiveInstallSession {
+ private final String mPackageName;
+ private final File mStagedDir;
+ private final IPackageInstallObserver2 mObserver;
+ private final PackageInstaller.SessionParams mSessionParams;
+ private final String mInstallerPackageName;
+ private final int mInstallerUid;
+ private final UserHandle mUser;
+ private final SigningDetails mSigningDetails;
+
+ ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, String installerPackageName,
+ int installerUid, UserHandle user, SigningDetails signingDetails) {
+ mPackageName = packageName;
+ mStagedDir = stagedDir;
+ mObserver = observer;
+ mSessionParams = sessionParams;
+ mInstallerPackageName = installerPackageName;
+ mInstallerUid = installerUid;
+ mUser = user;
+ mSigningDetails = signingDetails;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public File getStagedDir() {
+ return mStagedDir;
+ }
+
+ public IPackageInstallObserver2 getObserver() {
+ return mObserver;
+ }
+
+ public PackageInstaller.SessionParams getSessionParams() {
+ return mSessionParams;
+ }
+
+ public String getInstallerPackageName() {
+ return mInstallerPackageName;
+ }
+
+ public int getInstallerUid() {
+ return mInstallerUid;
+ }
+
+ public UserHandle getUser() {
+ return mUser;
+ }
+
+ public SigningDetails getSigningDetails() {
+ return mSigningDetails;
+ }
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 38bd172..31711e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -173,6 +173,8 @@
return runSetInstallLocation();
case "get-install-location":
return runGetInstallLocation();
+ case "install-add-session":
+ return runInstallAddSession();
case "move-package":
return runMovePackage();
case "move-primary-storage":
@@ -983,6 +985,23 @@
return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
}
+ private int runInstallAddSession() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final int parentSessionId = Integer.parseInt(getNextArg());
+
+ List<Integer> otherSessionIds = new ArrayList<>();
+ String opt;
+ while ((opt = getNextArg()) != null) {
+ otherSessionIds.add(Integer.parseInt(opt));
+ }
+ if (otherSessionIds.size() == 0) {
+ pw.println("Error: At least two sessions are required.");
+ return 1;
+ }
+ return doInstallAddSession(parentSessionId, ArrayUtils.convertToIntArray(otherSessionIds),
+ true /*logSuccess*/);
+ }
+
private int runInstallRemove() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
@@ -2268,6 +2287,9 @@
case "--apex":
sessionParams.installFlags |= PackageManager.INSTALL_APEX;
break;
+ case "--multi-package":
+ sessionParams.setMultiPackage();
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -2500,6 +2522,30 @@
}
}
+ private int doInstallAddSession(int parentId, int[] sessionIds, boolean logSuccess)
+ throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(
+ mInterface.getPackageInstaller().openSession(parentId));
+ if (!session.isMultiPackage()) {
+ getErrPrintWriter().println(
+ "Error: parent session ID is not a multi-package session");
+ return 1;
+ }
+ for (int i = 0; i < sessionIds.length; i++) {
+ session.addChildSessionId(sessionIds[i]);
+ }
+ if (logSuccess) {
+ pw.println("Success");
+ }
+ return 0;
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
@@ -2521,24 +2567,26 @@
}
}
- private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
+ private int doCommitSession(int sessionId, boolean logSuccess)
+ throws RemoteException {
+
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
-
- // Sanity check that all .dm files match an apk.
- // (The installer does not support standalone .dm files and will not process them.)
- try {
- DexMetadataHelper.validateDexPaths(session.getNames());
- } catch (IllegalStateException | IOException e) {
- pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+ if (!session.isMultiPackage()) {
+ // Sanity check that all .dm files match an apk.
+ // (The installer does not support standalone .dm files and will not process them.)
+ try {
+ DexMetadataHelper.validateDexPaths(session.getNames());
+ } catch (IllegalStateException | IOException e) {
+ pw.println(
+ "Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+ }
}
-
final LocalIntentReceiver receiver = new LocalIntentReceiver();
session.commit(receiver.getIntentSender());
-
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
@@ -2809,6 +2857,7 @@
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+ pw.println(" [--multi-package]");
pw.println(" Like \"install\", but starts an install session. Use \"install-write\"");
pw.println(" to push data into the session, and \"install-commit\" to finish.");
pw.println("");
@@ -2817,6 +2866,9 @@
pw.println(" will be read from stdin. Options are:");
pw.println(" -S: size in bytes of package, required for stdin");
pw.println("");
+ pw.println(" install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
+ pw.println(" Add one or more session IDs to a multi-package session.");
+ pw.println("");
pw.println(" install-commit SESSION_ID");
pw.println(" Commit the given active install session, installing the app.");
pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageSessionProvider.java b/services/core/java/com/android/server/pm/PackageSessionProvider.java
new file mode 100644
index 0000000..af11e77
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageSessionProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.pm;
+
+/** Provides access to individual sessions managed by the install service */
+public interface PackageSessionProvider {
+
+ /**
+ * Get the sessions for the provided session IDs. Null will be returned for session IDs that
+ * do not exist.
+ */
+ PackageInstallerSession getSession(int sessionId);
+
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e2818b7..13bb817 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -256,6 +257,7 @@
private static final String ATTR_USER_SET = "set";
private static final String ATTR_USER_FIXED = "fixed";
private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+ private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
// Flag mask of restored permission grants that are applied at install time
private static final int USER_RUNTIME_GRANT_MASK =
@@ -2775,13 +2777,13 @@
// dataPath - path to package's data path
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
+ // profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // frameworks/base/libs/packagelistparser
- // system/core/run-as/run-as.c
+ // system/core/libpackagelistparser
//
sb.setLength(0);
sb.append(ai.packageName);
@@ -2801,6 +2803,8 @@
} else {
sb.append("none");
}
+ sb.append(" ");
+ sb.append(ai.isProfileableByShell() ? "1" : "0");
sb.append("\n");
writer.append(sb);
}
@@ -5011,6 +5015,9 @@
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
pw.print(" revoke_on_upgrade");
}
+ if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ pw.print(" revoke_when_requested");
+ }
pw.println();
}
}
@@ -5326,6 +5333,11 @@
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
}
+ if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
+ != 0) {
+ serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
+ "true");
+ }
serializer.endTag(null, TAG_PERMISSION_ENTRY);
}
serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
@@ -5512,6 +5524,10 @@
if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
+ if ("true".equals(parser.getAttributeValue(null,
+ ATTR_REVOKE_WHEN_REQUESTED))) {
+ permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ }
if (isGranted || permBits != 0) {
rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 9d1a301..32b2bf0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
@@ -1009,6 +1010,41 @@
}
}
+ /**
+ * Check if a permission is already fixed or is set by the user.
+ *
+ * <p>A permission should not be set by the default policy if the user or other policies already
+ * set the permission.
+ *
+ * @param flags The flags of the permission
+ *
+ * @return {@code true} iff the permission can be set without violating a policy of the users
+ * intention
+ */
+ private boolean isFixedOrUserSet(int flags) {
+ return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+ | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
+ }
+
+ /**
+ * Return the background permission for a permission.
+ *
+ * @param permission The name of the foreground permission
+ *
+ * @return The name of the background permission or {@code null} if the permission has no
+ * background permission
+ */
+ private @Nullable String getBackgroundPermission(@NonNull String permission) {
+ try {
+ return mContext.getPackageManager().getPermissionInfo(permission,
+ 0).backgroundPermission;
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
private void grantRuntimePermissions(PackageInfo pkg,
Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
int userId) {
@@ -1021,9 +1057,15 @@
return;
}
+ PackageManager pm = mContext.getPackageManager();
final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
ApplicationInfo applicationInfo = pkg.applicationInfo;
+ int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ if (systemFixed) {
+ newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
// Automatically attempt to grant split permissions to older APKs
final List<PermissionManager.SplitPermissionInfo> splitPermissions =
mContext.getSystemService(PermissionManager.class).getSplitPermissions();
@@ -1063,9 +1105,28 @@
}
}
- final int grantablePermissionCount = requestedPermissions.length;
- for (int i = 0; i < grantablePermissionCount; i++) {
+ final int numRequestedPermissions = requestedPermissions.length;
+
+ // Sort requested permissions so that all permissions that are a foreground permission (i.e.
+ // permisions that have background permission) are before their background permissions.
+ final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
+ int numForeground = 0;
+ int numOther = 0;
+ for (int i = 0; i < numRequestedPermissions; i++) {
String permission = requestedPermissions[i];
+ if (getBackgroundPermission(permission) != null) {
+ sortedRequestedPermissions[numForeground] = permission;
+ numForeground++;
+ } else {
+ sortedRequestedPermissions[numRequestedPermissions - 1 - numOther] =
+ permission;
+ numOther++;
+ }
+ }
+
+ for (int requestedPermissionNum = 0; requestedPermissionNum < numRequestedPermissions;
+ requestedPermissionNum++) {
+ String permission = requestedPermissions[requestedPermissionNum];
// If there is a disabled system app it may request a permission the updated
// version ot the data partition doesn't, In this case skip the permission.
@@ -1078,13 +1139,14 @@
final int flags = mContext.getPackageManager().getPermissionFlags(
permission, pkg.packageName, user);
- // If any flags are set to the permission, then it is either set in
- // its current state by the system or device/profile owner or the user.
- // In all these cases we do not want to clobber the current state.
+ // Certain flags imply that the permission's current state by the system or
+ // device/profile owner or the user. In these cases we do not want to clobber the
+ // current state.
+ //
// Unless the caller wants to override user choices. The override is
// to make sure we can grant the needed permission to the default
// sms and phone apps after the user chooses this in the UI.
- if (flags == 0 || ignoreSystemPackage) {
+ if (!isFixedOrUserSet(flags) || ignoreSystemPackage) {
// Never clobber policy fixed permissions.
// We must allow the grant of a system-fixed permission because
// system-fixed is sticky, but the permission itself may be revoked.
@@ -1092,20 +1154,58 @@
continue;
}
+ int uid = UserHandle.getUid(userId,
+ UserHandle.getAppId(pkg.applicationInfo.uid));
+ String op = AppOpsManager.permissionToOp(permission);
+
mContext.getPackageManager()
.grantRuntimePermission(pkg.packageName, permission, user);
+
+ mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+ newFlags, newFlags, user);
+
+ List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
+ .get(permission);
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ String fgPerm = fgPerms.get(fgPermNum);
+
+ if (pm.checkPermission(fgPerm, pkg.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ // Upgrade the app-op state of the fg permission to allow bg access
+ mContext.getSystemService(AppOpsManager.class).setMode(
+ AppOpsManager.permissionToOp(fgPerm), uid,
+ pkg.packageName, AppOpsManager.MODE_ALLOWED);
+
+ break;
+ }
+ }
+ }
+
+ String bgPerm = getBackgroundPermission(permission);
+ if (bgPerm == null) {
+ if (op != null) {
+ mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+ pkg.packageName, AppOpsManager.MODE_ALLOWED);
+ }
+ } else {
+ int mode;
+ if (pm.checkPermission(bgPerm, pkg.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ mode = AppOpsManager.MODE_ALLOWED;
+ } else {
+ mode = AppOpsManager.MODE_FOREGROUND;
+ }
+
+ mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+ pkg.packageName, mode);
+ }
+
if (DEBUG) {
Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
+ permission + " to default handler " + pkg);
}
-
- int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- if (systemFixed) {
- newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- }
-
- mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
- newFlags, newFlags, user);
}
// If a component gets a permission for being the default handler A
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 18c6a3d..b788935 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -16,10 +16,28 @@
package com.android.server.pm.permission;
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.permissionToOp;
+import static android.app.AppOpsManager.permissionToOpCode;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.UserHandle.getAppId;
+import static android.os.UserHandle.getUid;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -30,6 +48,9 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -49,6 +70,7 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -152,6 +174,13 @@
@GuardedBy("mLock")
private boolean mSystemReady;
+ /**
+ * For each foreground/background permission the mapping:
+ * Background permission -> foreground permissions
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<String, List<String>> mBackgroundPermissions;
+
PermissionManagerService(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
@@ -680,8 +709,24 @@
}
}
- private void grantPermissions(PackageParser.Package pkg, boolean replace,
- String packageOfInterest, PermissionCallback callback) {
+ /**
+ * Restore the permission state for a package.
+ *
+ * <ul>
+ * <li>During boot the state gets restored from the disk</li>
+ * <li>During app update the state gets restored from the last version of the app</li>
+ * </ul>
+ *
+ * <p>This restores the permission state for all users.
+ *
+ * @param pkg the package the permissions belong to
+ * @param replace if the package is getting replaced (this might change the requested
+ * permissions of this package)
+ * @param packageOfInterest If this is the name of {@code pkg} add extra logging
+ * @param callback Result call back
+ */
+ private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+ @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
// IMPORTANT: There are two types of permissions: install and runtime.
// Install time permissions are granted when the app is installed to
// all device users and users added in the future. Runtime permissions
@@ -809,7 +854,8 @@
}
if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
+ Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ + pkg.packageName);
}
if (grant != GRANT_DENIED) {
@@ -998,6 +1044,11 @@
// changed.
ps.setInstallPermissionsFixed(true);
}
+
+ updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
+ updatedUserIds);
+ updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
+ permissionsState, pkg, updatedUserIds);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -1008,6 +1059,317 @@
}
}
+ /**
+ * Set app op for a app-op related to a permission.
+ *
+ * @param permission The permission the app-op belongs to
+ * @param pkg The package the permission belongs to
+ * @param userId The user to be changed
+ * @param mode The new mode to set
+ */
+ private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg,
+ @UserIdInt int userId, int mode) {
+ AppOpsManagerInternal appOpsInternal = LocalServices.getService(
+ AppOpsManagerInternal.class);
+
+ appOpsInternal.setMode(permissionToOpCode(permission),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkg.packageName, mode,
+ (pkg.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0);
+ }
+
+ /**
+ * Revoke permissions that are not implicit anymore and that have
+ * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
+ *
+ * @param ps The state of the permissions of the package
+ * @param pkg The package that is currently looked at
+ * @param updatedUserIds a list of user ids that needs to be amended if the permission state
+ * for a user is changed.
+ *
+ * @return The updated value of the {@code updatedUserIds} parameter
+ */
+ private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull int[] updatedUserIds) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ String pkgName = pkg.packageName;
+
+ int[] users = UserManagerService.getInstance().getUserIds();
+ int numUsers = users.length;
+ for (int i = 0; i < numUsers; i++) {
+ int userId = users[i];
+
+ for (String permission : ps.getPermissions(userId)) {
+ if (!pkg.implicitPermissions.contains(permission)) {
+ if (!ps.hasInstallPermission(permission)) {
+ int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
+
+ if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ BasePermission bp = mSettings.getPermissionLocked(permission);
+
+ ps.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+ | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET,
+ 0);
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds,
+ userId);
+
+ if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
+ == 0) {
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ if (permissionToOpCode(permission) != OP_NONE) {
+ setAppOpMode(permission, pkg, userId, MODE_IGNORED);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking app-op "
+ + permissionToOp(permission) + " for " + pkgName
+ + " as it is now requested");
+ }
+ }
+ } else {
+ int revokeResult = ps.revokeRuntimePermission(bp, userId);
+ if (revokeResult
+ != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking runtime permission " + permission
+ + " for " + pkgName
+ + " as it is now requested");
+ }
+ }
+ }
+
+ List<String> fgPerms = mBackgroundPermissions.get(permission);
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ String fgPerm = fgPerms.get(fgPermNum);
+
+ int mode = appOpsManager.unsafeCheckOpRaw(
+ permissionToOp(fgPerm),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)),
+ pkgName);
+
+ if (mode == MODE_ALLOWED) {
+ setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return updatedUserIds;
+ }
+
+ /**
+ * {@code newPerm} is newly added; Inherit the state from {@code sourcePerms}.
+ *
+ * <p>A single new permission can be split off from several source permissions. In this case
+ * the most leniant state is inherited.
+ *
+ * <p>Warning: This does not handle foreground / background permissions
+ *
+ * @param sourcePerms The permissions to inherit from
+ * @param newPerm The permission to inherit to
+ * @param ps The permission state of the package
+ * @param pkg The package requesting the permissions
+ * @param userId The user the permission belongs to
+ */
+ private void inheritPermissionStateToNewImplicitPermissionLocked(
+ @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @UserIdInt int userId) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ String pkgName = pkg.packageName;
+
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ if (permissionToOp(newPerm) != null) {
+ int mostLenientSourceMode = MODE_ERRORED;
+
+ // Find most lenient source permission state.
+ int numSourcePerms = sourcePerms.size();
+ for (int i = 0; i < numSourcePerms; i++) {
+ String sourcePerm = sourcePerms.valueAt(i);
+
+ if (ps.hasRuntimePermission(sourcePerm, userId)) {
+ String sourceOp = permissionToOp(sourcePerm);
+
+ if (sourceOp != null) {
+ int mode = appOpsManager.unsafeCheckOpRaw(sourceOp,
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
+
+ if (mode == MODE_FOREGROUND) {
+ throw new IllegalArgumentException("split permission" + sourcePerm
+ + " has app-op state " + AppOpsManager.MODE_NAMES[mode]);
+ }
+
+ // Leniency order: allowed > ignored > default
+ if (mode == MODE_ALLOWED) {
+ mostLenientSourceMode = MODE_ALLOWED;
+ break;
+ } else if (mode == MODE_IGNORED) {
+ mostLenientSourceMode = MODE_IGNORED;
+ } else if (mode == MODE_DEFAULT
+ && mostLenientSourceMode != MODE_IGNORED) {
+ mostLenientSourceMode = MODE_DEFAULT;
+ }
+ }
+ }
+ }
+
+ if (mostLenientSourceMode != MODE_ERRORED) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode
+ + " from " + sourcePerms + " for " + pkgName);
+ }
+
+ setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode);
+ }
+ }
+ } else {
+ boolean isGranted = false;
+
+ int numSourcePerm = sourcePerms.size();
+ for (int i = 0; i < numSourcePerm; i++) {
+ String sourcePerm = sourcePerms.valueAt(i);
+ if (ps.hasRuntimePermission(sourcePerm, userId)
+ && ps.getRuntimePermissionState(sourcePerm, userId).isGranted()) {
+ isGranted = true;
+ break;
+ }
+ }
+
+ if (isGranted) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms
+ + " for " + pkgName);
+ }
+
+ ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
+ }
+ }
+ }
+
+ /**
+ * Set the state of a implicit permission that is seen for the first time.
+ *
+ * @param origPs The permission state of the package before the split
+ * @param ps The new permission state
+ * @param pkg The package the permission belongs to
+ * @param updatedUserIds List of users for which the permission state has already been changed
+ *
+ * @return List of users for which the permission state has been changed
+ */
+ private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
+ @NonNull PermissionsState origPs,
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull int[] updatedUserIds) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ String pkgName = pkg.packageName;
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
+
+ int numRequestedPerms = pkg.requestedPermissions.size();
+ for (int i = 0; i < numRequestedPerms; i++) {
+ BasePermission bp = mSettings.getPermissionLocked(pkg.requestedPermissions.get(i));
+ if (bp != null) {
+ String perm = bp.getName();
+
+ if (!origPs.hasRequestedPermission(perm) && pkg.implicitPermissions.contains(
+ perm)) {
+ newImplicitPermissions.add(perm);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, perm + " is newly added for " + pkgName);
+ }
+ }
+ }
+ }
+
+ ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
+
+ int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ PermissionManager.SplitPermissionInfo spi =
+ PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+
+ List<String> newPerms = spi.getNewPermissions();
+ int numNewPerms = newPerms.size();
+ for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
+ String newPerm = newPerms.get(newPermNum);
+
+ ArraySet<String> splitPerms = newToSplitPerms.get(newPerm);
+ if (splitPerms == null) {
+ splitPerms = new ArraySet<>();
+ newToSplitPerms.put(newPerm, splitPerms);
+ }
+
+ splitPerms.add(spi.getSplitPermission());
+ }
+ }
+
+ int numNewImplicitPerms = newImplicitPermissions.size();
+ for (int newImplicitPermNum = 0; newImplicitPermNum < numNewImplicitPerms;
+ newImplicitPermNum++) {
+ String newPerm = newImplicitPermissions.valueAt(newImplicitPermNum);
+ ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm);
+
+ if (sourcePerms != null) {
+ if (!ps.hasInstallPermission(newPerm)) {
+ BasePermission bp = mSettings.getPermissionLocked(newPerm);
+
+ int[] users = UserManagerService.getInstance().getUserIds();
+ int numUsers = users.length;
+ for (int userNum = 0; userNum < numUsers; userNum++) {
+ int userId = users[userNum];
+
+ ps.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+
+ // SPECIAL BEHAVIOR for background location. Foreground only by default.
+ if (newPerm.equals(ACCESS_BACKGROUND_LOCATION)) {
+ int numSourcePerms = sourcePerms.size();
+ for (int sourcePermNum = 0; sourcePermNum < numSourcePerms;
+ sourcePermNum++) {
+ String sourcePerm = sourcePerms.valueAt(sourcePermNum);
+
+ if (appOpsManager.unsafeCheckOpNoThrow(permissionToOp(sourcePerm),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName)
+ == MODE_ALLOWED) {
+ setAppOpMode(sourcePerm, pkg, userId, MODE_FOREGROUND);
+ }
+ }
+ } else {
+ if (!origPs.hasRequestedPermission(sourcePerms)) {
+ // Both permissions are new, do nothing
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+ + " for " + pkgName
+ + " as split permission is also new");
+ }
+
+ break;
+ } else {
+ inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
+ newPerm, ps, pkg, userId);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return updatedUserIds;
+ }
+
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -1754,7 +2116,30 @@
// and make sure there are no dangling permissions.
flags = updatePermissions(changingPkgName, changingPkg, flags);
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
+ synchronized (mLock) {
+ if (mBackgroundPermissions == null) {
+ // Cache background -> foreground permission mapping.
+ // Only system declares background permissions, hence mapping does never change.
+ mBackgroundPermissions = new ArrayMap<>();
+ for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
+ if (bp.perm != null && bp.perm.info != null
+ && bp.perm.info.backgroundPermission != null) {
+ String fgPerm = bp.name;
+ String bgPerm = bp.perm.info.backgroundPermission;
+
+ List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
+ if (fgPerms == null) {
+ fgPerms = new ArrayList<>();
+ mBackgroundPermissions.put(bgPerm, fgPerms);
+ }
+
+ fgPerms.add(fgPerm);
+ }
+ }
+ }
+ }
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
@@ -1764,7 +2149,7 @@
final String volumeUuid = getVolumeUuidForPackage(pkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissions(pkg, replace, changingPkgName, callback);
+ restorePermissionState(pkg, replace, changingPkgName, callback);
}
}
}
@@ -1774,7 +2159,7 @@
final String volumeUuid = getVolumeUuidForPackage(changingPkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissions(changingPkg, replace, changingPkgName, callback);
+ restorePermissionState(changingPkg, replace, changingPkgName, callback);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -2071,6 +2456,17 @@
mMetricsLogger.write(log);
}
+ /**
+ * Get the mapping of background permissions to their foreground permissions.
+ *
+ * <p>Only initialized in the system server.
+ *
+ * @return the map <bg permission -> list<fg perm>>
+ */
+ public @Nullable ArrayMap<String, List<String>> getBackgroundPermissions() {
+ return mBackgroundPermissions;
+ }
+
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
@Override
public void systemReady() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1dae396..97af045 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -41,6 +41,7 @@
import static android.os.Build.VERSION_CODES.O;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.STATE_OFF;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
@@ -155,6 +156,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.AppOpsManager;
@@ -665,9 +667,6 @@
SleepToken mDreamingSleepToken;
SleepToken mScreenOffSleepToken;
volatile boolean mKeyguardOccluded;
- boolean mHomePressed;
- boolean mHomeConsumed;
- boolean mHomeDoubleTapPending;
Intent mHomeIntent;
Intent mCarDockIntent;
Intent mDeskDockIntent;
@@ -865,7 +864,7 @@
launchVoiceAssistWithWakeLock();
break;
case MSG_POWER_DELAYED_PRESS:
- powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
+ powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
finishPowerKeyPress();
break;
case MSG_POWER_LONG_PRESS:
@@ -1340,7 +1339,7 @@
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
- launchHomeFromHotKey();
+ launchHomeFromHotKey(DEFAULT_DISPLAY);
break;
case SHORT_PRESS_POWER_GO_HOME:
shortPressPowerGoHome();
@@ -1369,7 +1368,8 @@
}
private void shortPressPowerGoHome() {
- launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
+ launchHomeFromHotKey(DEFAULT_DISPLAY, true /* awakenFromDreams */,
+ false /*respectKeyguard*/);
if (isKeyguardShowingAndNotOccluded()) {
// Notify keyguard so it can do any special handling for the power button since the
// device will not power off and only launch home.
@@ -1505,7 +1505,8 @@
private void sleepPress() {
if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) {
- launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/);
+ launchHomeFromHotKey(DEFAULT_DISPLAY, false /* awakenDreams */,
+ true /*respectKeyguard*/);
}
}
@@ -1683,7 +1684,7 @@
Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
}
- private void handleShortPressOnHome() {
+ private void handleShortPressOnHome(int displayId) {
// Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
final HdmiControl hdmiControl = getHdmiControl();
if (hdmiControl != null) {
@@ -1698,7 +1699,7 @@
}
// Go home!
- launchHomeFromHotKey();
+ launchHomeFromHotKey(displayId);
}
/**
@@ -1745,26 +1746,6 @@
}
}
- private void handleLongPressOnHome(int deviceId) {
- if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
- return;
- }
- mHomeConsumed = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
- "Home - Long Press");
- switch (mLongPressOnHomeBehavior) {
- case LONG_PRESS_HOME_ALL_APPS:
- launchAllAppsAction();
- break;
- case LONG_PRESS_HOME_ASSIST:
- launchAssistAction(null, deviceId);
- break;
- default:
- Log.w(TAG, "Undefined home long press behavior: " + mLongPressOnHomeBehavior);
- break;
- }
- }
-
private void launchAllAppsAction() {
Intent intent = new Intent(Intent.ACTION_ALL_APPS);
if (mHasFeatureLeanback) {
@@ -1781,13 +1762,6 @@
startActivityAsUser(intent, UserHandle.CURRENT);
}
- private void handleDoubleTapOnHome() {
- if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mHomeConsumed = true;
- toggleRecentApps();
- }
- }
-
private void showPictureInPictureMenu(KeyEvent event) {
if (DEBUG_INPUT) Log.d(TAG, "showPictureInPictureMenu event=" + event);
mHandler.removeMessages(MSG_SHOW_PICTURE_IN_PICTURE_MENU);
@@ -1803,15 +1777,147 @@
}
}
- private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- if (mHomeDoubleTapPending) {
- mHomeDoubleTapPending = false;
- handleShortPressOnHome();
+ /** A handler to handle home keys per display */
+ private class DisplayHomeButtonHandler {
+
+ private final int mDisplayId;
+
+ private boolean mHomeDoubleTapPending;
+ private boolean mHomePressed;
+ private boolean mHomeConsumed;
+
+ private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mHomeDoubleTapPending) {
+ mHomeDoubleTapPending = false;
+ handleShortPressOnHome(mDisplayId);
+ }
+ }
+ };
+
+ DisplayHomeButtonHandler(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ int handleHomeButton(WindowState win, KeyEvent event) {
+ final boolean keyguardOn = keyguardOn();
+ final int repeatCount = event.getRepeatCount();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
+
+ if (DEBUG_INPUT) {
+ Log.d(TAG, String.format("handleHomeButton in display#%d mHomePressed = %b",
+ mDisplayId, mHomePressed));
+ }
+
+ // If we have released the home key, and didn't do anything else
+ // while it was pressed, then it is time to go home!
+ if (!down) {
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ cancelPreloadRecentApps();
+ }
+
+ mHomePressed = false;
+ if (mHomeConsumed) {
+ mHomeConsumed = false;
+ return -1;
+ }
+
+ if (canceled) {
+ Log.i(TAG, "Ignoring HOME; event canceled.");
+ return -1;
+ }
+
+ // Delay handling home if a double-tap is possible.
+ if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
+ mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
+ mHomeDoubleTapPending = true;
+ mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
+ ViewConfiguration.getDoubleTapTimeout());
+ return -1;
+ }
+
+ handleShortPressOnHome(mDisplayId);
+ return -1;
+ }
+
+ // If a system window has focus, then it doesn't make sense
+ // right now to interact with applications.
+ WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
+ if (attrs != null) {
+ final int type = attrs.type;
+ if (type == TYPE_KEYGUARD_DIALOG
+ || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+ // the "app" is keyguard, so give it the key
+ return 0;
+ }
+ for (int t : WINDOW_TYPES_WHERE_HOME_DOESNT_WORK) {
+ if (type == t) {
+ // don't do anything, but also don't pass it to the app
+ return -1;
+ }
+ }
+ }
+
+ // Remember that home is pressed and handle special actions.
+ if (repeatCount == 0) {
+ mHomePressed = true;
+ if (mHomeDoubleTapPending) {
+ mHomeDoubleTapPending = false;
+ mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
+ handleDoubleTapOnHome();
+ // TODO(multi-display): Remove display id check once we support recents on
+ // multi-display
+ } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI
+ && mDisplayId == DEFAULT_DISPLAY) {
+ preloadRecentApps();
+ }
+ } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ if (!keyguardOn) {
+ handleLongPressOnHome(event.getDeviceId());
+ }
+ }
+ return -1;
+ }
+
+ private void handleDoubleTapOnHome() {
+ if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+ mHomeConsumed = true;
+ toggleRecentApps();
}
}
- };
+
+ private void handleLongPressOnHome(int deviceId) {
+ if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
+ return;
+ }
+ mHomeConsumed = true;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ "Home - Long Press");
+ switch (mLongPressOnHomeBehavior) {
+ case LONG_PRESS_HOME_ALL_APPS:
+ launchAllAppsAction();
+ break;
+ case LONG_PRESS_HOME_ASSIST:
+ launchAssistAction(null, deviceId);
+ break;
+ default:
+ Log.w(TAG, "Undefined home long press behavior: "
+ + mLongPressOnHomeBehavior);
+ break;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("mDisplayId = %d, mHomePressed = %b", mDisplayId, mHomePressed);
+ }
+ }
+
+ /** A DisplayHomeButtonHandler map indexed by display id */
+ private final SparseArray<DisplayHomeButtonHandler> mDisplayHomeButtonHandlers =
+ new SparseArray<>();
private boolean isRoundWindow() {
return mContext.getResources().getConfiguration().isScreenRound();
@@ -3259,6 +3365,7 @@
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
};
+ // TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
@@ -3269,11 +3376,11 @@
final int flags = event.getFlags();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
+ final int displayId = event.getDisplayId();
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
- + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
- + " canceled=" + canceled);
+ + repeatCount + " keyguardOn=" + keyguardOn + " canceled=" + canceled);
}
// If we think we might have a volume down & power key chord on the way
@@ -3358,71 +3465,12 @@
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
-
- // If we have released the home key, and didn't do anything else
- // while it was pressed, then it is time to go home!
- if (!down) {
- cancelPreloadRecentApps();
-
- mHomePressed = false;
- if (mHomeConsumed) {
- mHomeConsumed = false;
- return -1;
- }
-
- if (canceled) {
- Log.i(TAG, "Ignoring HOME; event canceled.");
- return -1;
- }
-
- // Delay handling home if a double-tap is possible.
- if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
- mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
- mHomeDoubleTapPending = true;
- mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
- ViewConfiguration.getDoubleTapTimeout());
- return -1;
- }
-
- handleShortPressOnHome();
- return -1;
+ DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+ if (handler == null) {
+ handler = new DisplayHomeButtonHandler(displayId);
+ mDisplayHomeButtonHandlers.put(displayId, handler);
}
-
- // If a system window has focus, then it doesn't make sense
- // right now to interact with applications.
- WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (attrs != null) {
- final int type = attrs.type;
- if (type == TYPE_KEYGUARD_DIALOG
- || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- // the "app" is keyguard, so give it the key
- return 0;
- }
- final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
- for (int i=0; i<typeCount; i++) {
- if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
- // don't do anything, but also don't pass it to the app
- return -1;
- }
- }
- }
-
- // Remember that home is pressed and handle special actions.
- if (repeatCount == 0) {
- mHomePressed = true;
- if (mHomeDoubleTapPending) {
- mHomeDoubleTapPending = false;
- mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
- handleDoubleTapOnHome();
- } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- preloadRecentApps();
- }
- } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- if (!keyguardOn) {
- handleLongPressOnHome(event.getDeviceId());
- }
- }
- return -1;
+ return handler.handleHomeButton(win, event);
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
// Hijack modified menu keys for debugging features
final int chordBug = KeyEvent.META_SHIFT_ON;
@@ -3820,6 +3868,7 @@
}
}
+ // TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
@@ -3862,7 +3911,7 @@
event.getAction(), fallbackAction.keyCode,
event.getRepeatCount(), fallbackAction.metaState,
event.getDeviceId(), event.getScanCode(),
- flags, event.getSource(), null);
+ flags, event.getSource(), event.getDisplayId(), null);
if (!interceptFallback(win, fallbackEvent, policyFlags)) {
fallbackEvent.recycle();
@@ -3991,8 +4040,12 @@
}
private void startActivityAsUser(Intent intent, UserHandle handle) {
+ startActivityAsUser(intent, null, handle);
+ }
+
+ private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle) {
if (isUserSetupComplete()) {
- mContext.startActivityAsUser(intent, handle);
+ mContext.startActivityAsUser(intent, bundle, handle);
} else {
Slog.i(TAG, "Not starting activity because user setup is in progress: " + intent);
}
@@ -4067,15 +4120,16 @@
}
}
- void launchHomeFromHotKey() {
- launchHomeFromHotKey(true /* awakenFromDreams */, true /*respectKeyguard*/);
+ void launchHomeFromHotKey(int displayId) {
+ launchHomeFromHotKey(displayId, true /* awakenFromDreams */, true /*respectKeyguard*/);
}
/**
* A home key -> launch home action was detected. Take the appropriate action
* given the situation with the keyguard.
*/
- void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
+ void launchHomeFromHotKey(int displayId, final boolean awakenFromDreams,
+ final boolean respectKeyguard) {
// Abort possibly stuck animations.
mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
@@ -4092,7 +4146,7 @@
@Override
public void onKeyguardExitResult(boolean success) {
if (success) {
- startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
+ startDockOrHome(displayId, true /*fromHomeKey*/, awakenFromDreams);
}
}
});
@@ -4113,7 +4167,7 @@
hideRecentApps(false, true);
} else {
// Otherwise, just launch Home
- startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
+ startDockOrHome(displayId, true /*fromHomeKey*/, awakenFromDreams);
}
}
@@ -5677,7 +5731,7 @@
mDefaultDisplayPolicy.setHdmiPlugged(plugged, true /* force */);
}
-
+ // TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -5690,6 +5744,7 @@
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
+ final int displayId = event.getDisplayId();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -6193,7 +6248,7 @@
return true;
}
-
+ // TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
@@ -7269,7 +7324,7 @@
return null;
}
- void startDockOrHome(boolean fromHomeKey, boolean awakenFromDreams) {
+ void startDockOrHome(int displayId, boolean fromHomeKey, boolean awakenFromDreams) {
try {
ActivityManager.getService().stopAppSwitches();
} catch (RemoteException e) {}
@@ -7299,8 +7354,13 @@
} else {
intent = mHomeIntent;
}
+ final Bundle bundle = getLaunchDisplayIdBundle(displayId);
+ startActivityAsUser(intent, bundle, UserHandle.CURRENT);
+ }
- startActivityAsUser(intent, UserHandle.CURRENT);
+ private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
+ return (displayId == INVALID_DISPLAY) ? null
+ : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
}
/**
@@ -7314,7 +7374,7 @@
}
if (false) {
// This code always brings home to the front.
- startDockOrHome(false /*fromHomeKey*/, true /* awakenFromDreams */);
+ startDockOrHome(DEFAULT_DISPLAY, false /*fromHomeKey*/, true /* awakenFromDreams */);
} else {
// This code brings home to the front or, if it is already
// at the front, puts the device to sleep.
@@ -7325,7 +7385,7 @@
} else {
ActivityManager.getService().stopAppSwitches();
sendCloseSystemWindows();
- Intent dock = createHomeDockIntent();
+ final Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityTaskManager.getService()
.startActivityAsUser(null, null, dock,
@@ -8013,7 +8073,13 @@
pw.print(incallBackBehaviorToString(mIncallBackBehavior));
pw.print(" mEndcallBehavior=");
pw.println(endcallBehaviorToString(mEndcallBehavior));
- pw.print(prefix); pw.print("mHomePressed="); pw.println(mHomePressed);
+ pw.print(prefix);
+ // TODO(b/117479243): handle it in InputPolicy
+ pw.print("mDisplayHomeButtonHandlers=");
+ for (int i = 0; i < mDisplayHomeButtonHandlers.size(); i++) {
+ final int key = mDisplayHomeButtonHandlers.keyAt(i);
+ pw.println(mDisplayHomeButtonHandlers.get(key));
+ }
pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 5323b1f..6d7b04c 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -57,9 +57,6 @@
public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
- // Secure setting for GPS behavior when battery saver mode is on.
- public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
-
private static final String KEY_GPS_MODE = "gps_mode";
private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
@@ -101,6 +98,28 @@
private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
+ private static final Policy sDefaultPolicy = new Policy(
+ 0.5f, /* adjustBrightnessFactor */
+ true, /* deferFullBackup */
+ true, /* deferKeyValueBackup */
+ false, /* disableAnimation */
+ true, /* disableAod */
+ true, /* disableLaunchBoost */
+ true, /* disableOptionalSensors */
+ true, /* disableSoundTrigger */
+ true, /* disableVibration */
+ false, /* enableAdjustBrightness */
+ false, /* enableDataSaver */
+ true, /* enableFirewall */
+ false, /* enableQuickDoze */
+ new ArrayMap<>(), /* filesForInteractive */
+ new ArrayMap<>(), /* filesForNoninteractive */
+ true, /* forceAllAppsStandby */
+ true, /* forceBackgroundCheck */
+ PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* gpsMode */
+ false /* sendTronLog */
+ );
+
private final Object mLock;
private final Handler mHandler;
@@ -120,146 +139,20 @@
private String mEventLogKeys;
/**
- * {@code true} if vibration is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_VIBRATION_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mVibrationDisabledConfig;
-
- /**
- * Whether vibration should *really* be disabled -- i.e. {@link #mVibrationDisabledConfig}
+ * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
* is true *and* {@link #mAccessibilityEnabled} is false.
*/
@GuardedBy("mLock")
- private boolean mVibrationDisabledEffective;
+ private boolean mDisableVibrationEffective;
/**
- * {@code true} if animation is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ANIMATION_DISABLED
+ * Whether accessibility is currently enabled or not.
*/
@GuardedBy("mLock")
- private boolean mAnimationDisabled;
+ private boolean mAccessibilityEnabled;
- /**
- * {@code true} if sound trigger is disabled in battery saver mode
- * in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_SOUNDTRIGGER_DISABLED
- */
@GuardedBy("mLock")
- private boolean mSoundTriggerDisabled;
-
- /**
- * {@code true} if full backup is deferred in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_FULLBACKUP_DEFERRED
- */
- @GuardedBy("mLock")
- private boolean mFullBackupDeferred;
-
- /**
- * {@code true} if key value backup is deferred in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_KEYVALUE_DEFERRED
- */
- @GuardedBy("mLock")
- private boolean mKeyValueBackupDeferred;
-
- /**
- * {@code true} if network policy firewall should be turned on in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ACTIVATE_FIREWALL_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mEnableFirewall;
-
- /**
- * {@code true} if low power mode brightness adjustment should be turned on in battery saver
- * mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mEnableAdjustBrightness;
-
- /**
- * {@code true} if data saver should be turned on in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ACTIVATE_DATASAVER_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mEnableDataSaver;
-
- /**
- * {@code true} if launch boost should be disabled on battery saver.
- */
- @GuardedBy("mLock")
- private boolean mLaunchBoostDisabled;
-
- /**
- * This is the flag to decide the gps mode in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_GPS_MODE
- */
- @GuardedBy("mLock")
- private int mGpsMode;
-
- /**
- * This is the flag to decide the how much to adjust the screen brightness. This is
- * the float value from 0 to 1 where 1 means don't change brightness.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
- */
- @GuardedBy("mLock")
- private float mAdjustBrightnessFactor;
-
- /**
- * Whether to put all apps in the stand-by mode.
- */
- @GuardedBy("mLock")
- private boolean mForceAllAppsStandby;
-
- /**
- * Whether to put all apps in the stand-by mode.
- */
- @GuardedBy("mLock")
- private boolean mForceBackgroundCheck;
-
- /**
- * Whether to show non-essential sensors (e.g. edge sensors) or not.
- */
- @GuardedBy("mLock")
- private boolean mOptionalSensorsDisabled;
-
- /**
- * Whether AOD is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mAodDisabled;
-
- /**
- * Whether Quick Doze is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mQuickDozeEnabled;
-
- /**
- * Whether BatterySavingStats should send tron events.
- */
- @GuardedBy("mLock")
- private boolean mSendTronLog;
+ private Policy mCurrPolicy = sDefaultPolicy;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -268,30 +161,6 @@
@GuardedBy("mLock")
private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
- /**
- * List of [Filename -> content] that should be written when battery saver is activated
- * and the device is interactive.
- *
- * We use this to change the max CPU frequencies.
- */
- @GuardedBy("mLock")
- private ArrayMap<String, String> mFilesForInteractive;
-
- /**
- * List of [Filename -> content] that should be written when battery saver is activated
- * and the device is non-interactive.
- *
- * We use this to change the max CPU frequencies.
- */
- @GuardedBy("mLock")
- private ArrayMap<String, String> mFilesForNoninteractive;
-
- /**
- * Whether accessibility is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mAccessibilityEnabled;
-
public interface BatterySaverPolicyListener {
void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
}
@@ -399,36 +268,7 @@
final KeyValueListParser parser = new KeyValueListParser(',');
- // Non-device-specific parameters.
- try {
- parser.setString(setting);
- } catch (IllegalArgumentException e) {
- Slog.wtf(TAG, "Bad battery saver constants: " + setting);
- }
-
- mVibrationDisabledConfig = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
- mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, false);
- mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
- mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
- mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
- mEnableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED, false);
- mEnableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
- mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
- mEnableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED, true);
- mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
- mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
- mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
- mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
- mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
- mQuickDozeEnabled = parser.getBoolean(KEY_QUICK_DOZE_ENABLED, false);
- mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
-
- // Get default value from Settings.Secure
- final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
- mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
-
- // Non-device-specific parameters.
+ // Device-specific parameters.
try {
parser.setString(deviceSpecificSetting);
} catch (IllegalArgumentException e) {
@@ -436,41 +276,280 @@
+ deviceSpecificSetting);
}
- mFilesForInteractive = (new CpuFrequencies()).parseString(
- parser.getString(KEY_CPU_FREQ_INTERACTIVE, "")).toSysFileMap();
+ final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
+ final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
- mFilesForNoninteractive = (new CpuFrequencies()).parseString(
- parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
+ // Non-device-specific parameters.
+ try {
+ parser.setString(setting);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad battery saver constants: " + setting);
+ }
+
+ float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
+ sDefaultPolicy.adjustBrightnessFactor);
+ boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
+ sDefaultPolicy.deferFullBackup);
+ boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
+ sDefaultPolicy.deferKeyValueBackup);
+ boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
+ sDefaultPolicy.disableAnimation);
+ boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, sDefaultPolicy.disableAod);
+ boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
+ sDefaultPolicy.disableLaunchBoost);
+ boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
+ sDefaultPolicy.disableOptionalSensors);
+ boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
+ sDefaultPolicy.disableSoundTrigger);
+ boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
+ sDefaultPolicy.disableVibration);
+ boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
+ !sDefaultPolicy.enableAdjustBrightness);
+ boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
+ !sDefaultPolicy.enableDataSaver);
+ boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
+ !sDefaultPolicy.enableFirewall);
+ boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
+ sDefaultPolicy.enableQuickDoze);
+ boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
+ sDefaultPolicy.forceAllAppsStandby);
+ boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
+ sDefaultPolicy.forceBackgroundCheck);
+ int gpsMode = parser.getInt(KEY_GPS_MODE, sDefaultPolicy.gpsMode);
+ boolean sendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, sDefaultPolicy.sendTronLog);
+
+ mCurrPolicy = new Policy(
+ adjustBrightnessFactor,
+ deferFullBackup,
+ deferKeyValueBackup,
+ disableAnimation,
+ disableAod,
+ disableLaunchBoost,
+ disableOptionalSensors,
+ disableSoundTrigger,
+ /* disableVibration */
+ disableVibrationConfig,
+ enableAdjustBrightness,
+ enableDataSaver,
+ enableFirewall,
+ enableQuickDoze,
+ /* filesForInteractive */
+ (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
+ /* filesForNoninteractive */
+ (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
+ forceAllAppsStandby,
+ forceBackgroundCheck,
+ gpsMode,
+ sendTronLog
+ );
// Update the effective policy.
- mVibrationDisabledEffective = mVibrationDisabledConfig
+ mDisableVibrationEffective = mCurrPolicy.disableVibration
&& !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
final StringBuilder sb = new StringBuilder();
- if (mForceAllAppsStandby) sb.append("A");
- if (mForceBackgroundCheck) sb.append("B");
+ if (mCurrPolicy.forceAllAppsStandby) sb.append("A");
+ if (mCurrPolicy.forceBackgroundCheck) sb.append("B");
- if (mVibrationDisabledEffective) sb.append("v");
- if (mAnimationDisabled) sb.append("a");
- if (mSoundTriggerDisabled) sb.append("s");
- if (mFullBackupDeferred) sb.append("F");
- if (mKeyValueBackupDeferred) sb.append("K");
- if (mEnableFirewall) sb.append("f");
- if (mEnableDataSaver) sb.append("d");
- if (mEnableAdjustBrightness) sb.append("b");
+ if (mDisableVibrationEffective) sb.append("v");
+ if (mCurrPolicy.disableAnimation) sb.append("a");
+ if (mCurrPolicy.disableSoundTrigger) sb.append("s");
+ if (mCurrPolicy.deferFullBackup) sb.append("F");
+ if (mCurrPolicy.deferKeyValueBackup) sb.append("K");
+ if (mCurrPolicy.enableFirewall) sb.append("f");
+ if (mCurrPolicy.enableDataSaver) sb.append("d");
+ if (mCurrPolicy.enableAdjustBrightness) sb.append("b");
- if (mLaunchBoostDisabled) sb.append("l");
- if (mOptionalSensorsDisabled) sb.append("S");
- if (mAodDisabled) sb.append("o");
- if (mQuickDozeEnabled) sb.append("q");
- if (mSendTronLog) sb.append("t");
+ if (mCurrPolicy.disableLaunchBoost) sb.append("l");
+ if (mCurrPolicy.disableOptionalSensors) sb.append("S");
+ if (mCurrPolicy.disableAod) sb.append("o");
+ if (mCurrPolicy.enableQuickDoze) sb.append("q");
+ if (mCurrPolicy.sendTronLog) sb.append("t");
- sb.append(mGpsMode);
+ sb.append(mCurrPolicy.gpsMode);
mEventLogKeys = sb.toString();
- mBatterySavingStats.setSendTronLog(mSendTronLog);
+ mBatterySavingStats.setSendTronLog(mCurrPolicy.sendTronLog);
+ }
+
+ private static class Policy {
+ /**
+ * This is the flag to decide the how much to adjust the screen brightness. This is
+ * the float value from 0 to 1 where 1 means don't change brightness.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
+ */
+ public final float adjustBrightnessFactor;
+
+ /**
+ * {@code true} if full backup is deferred in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_FULLBACKUP_DEFERRED
+ */
+ public final boolean deferFullBackup;
+
+ /**
+ * {@code true} if key value backup is deferred in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_KEYVALUE_DEFERRED
+ */
+ public final boolean deferKeyValueBackup;
+
+ /**
+ * {@code true} if animation is disabled in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ANIMATION_DISABLED
+ */
+ public final boolean disableAnimation;
+
+ /**
+ * {@code true} if AOD is disabled in battery saver mode.
+ */
+ public final boolean disableAod;
+
+ /**
+ * {@code true} if launch boost should be disabled on battery saver.
+ */
+ public final boolean disableLaunchBoost;
+
+ /**
+ * Whether to show non-essential sensors (e.g. edge sensors) or not.
+ */
+ public final boolean disableOptionalSensors;
+
+ /**
+ * {@code true} if sound trigger is disabled in battery saver mode
+ * in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_SOUNDTRIGGER_DISABLED
+ */
+ public final boolean disableSoundTrigger;
+
+ /**
+ * {@code true} if vibration is disabled in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_VIBRATION_DISABLED
+ */
+ public final boolean disableVibration;
+
+ /**
+ * {@code true} if low power mode brightness adjustment should be turned on in battery saver
+ * mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+ */
+ public final boolean enableAdjustBrightness;
+
+ /**
+ * {@code true} if data saver should be turned on in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ACTIVATE_DATASAVER_DISABLED
+ */
+ public final boolean enableDataSaver;
+
+ /**
+ * {@code true} if network policy firewall should be turned on in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ACTIVATE_FIREWALL_DISABLED
+ */
+ public final boolean enableFirewall;
+
+ /**
+ * Whether Quick Doze is enabled or not.
+ */
+ public final boolean enableQuickDoze;
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the device is interactive.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ public final ArrayMap<String, String> filesForInteractive;
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the device is non-interactive.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ public final ArrayMap<String, String> filesForNoninteractive;
+
+ /**
+ * Whether to put all apps in the stand-by mode.
+ */
+ public final boolean forceAllAppsStandby;
+
+ /**
+ * Whether to put all apps in the stand-by mode.
+ */
+ public final boolean forceBackgroundCheck;
+
+ /**
+ * This is the flag to decide the gps mode in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_GPS_MODE
+ */
+ public final int gpsMode;
+
+ /**
+ * Whether BatterySavingStats should send tron events.
+ */
+ public final boolean sendTronLog;
+
+ Policy(
+ float adjustBrightnessFactor,
+ boolean deferFullBackup,
+ boolean deferKeyValueBackup,
+ boolean disableAnimation,
+ boolean disableAod,
+ boolean disableLaunchBoost,
+ boolean disableOptionalSensors,
+ boolean disableSoundTrigger,
+ boolean disableVibration,
+ boolean enableAdjustBrightness,
+ boolean enableDataSaver,
+ boolean enableFirewall,
+ boolean enableQuickDoze,
+ ArrayMap<String, String> filesForInteractive,
+ ArrayMap<String, String> filesForNoninteractive,
+ boolean forceAllAppsStandby,
+ boolean forceBackgroundCheck,
+ int gpsMode,
+ boolean sendTronLog) {
+
+ this.adjustBrightnessFactor = adjustBrightnessFactor;
+ this.deferFullBackup = deferFullBackup;
+ this.deferKeyValueBackup = deferKeyValueBackup;
+ this.disableAnimation = disableAnimation;
+ this.disableAod = disableAod;
+ this.disableLaunchBoost = disableLaunchBoost;
+ this.disableOptionalSensors = disableOptionalSensors;
+ this.disableSoundTrigger = disableSoundTrigger;
+ this.disableVibration = disableVibration;
+ this.enableAdjustBrightness = enableAdjustBrightness;
+ this.enableDataSaver = enableDataSaver;
+ this.enableFirewall = enableFirewall;
+ this.enableQuickDoze = enableQuickDoze;
+ this.filesForInteractive = filesForInteractive;
+ this.filesForNoninteractive = filesForNoninteractive;
+ this.forceAllAppsStandby = forceAllAppsStandby;
+ this.forceBackgroundCheck = forceBackgroundCheck;
+ this.gpsMode = gpsMode;
+ this.sendTronLog = sendTronLog;
+ }
}
/**
@@ -493,47 +572,47 @@
switch (type) {
case ServiceType.GPS:
return builder.setBatterySaverEnabled(realMode)
- .setGpsMode(mGpsMode)
+ .setGpsMode(mCurrPolicy.gpsMode)
.build();
case ServiceType.ANIMATION:
- return builder.setBatterySaverEnabled(mAnimationDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableAnimation)
.build();
case ServiceType.FULL_BACKUP:
- return builder.setBatterySaverEnabled(mFullBackupDeferred)
+ return builder.setBatterySaverEnabled(mCurrPolicy.deferFullBackup)
.build();
case ServiceType.KEYVALUE_BACKUP:
- return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
+ return builder.setBatterySaverEnabled(mCurrPolicy.deferKeyValueBackup)
.build();
case ServiceType.NETWORK_FIREWALL:
- return builder.setBatterySaverEnabled(mEnableFirewall)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableFirewall)
.build();
case ServiceType.SCREEN_BRIGHTNESS:
- return builder.setBatterySaverEnabled(mEnableAdjustBrightness)
- .setBrightnessFactor(mAdjustBrightnessFactor)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableAdjustBrightness)
+ .setBrightnessFactor(mCurrPolicy.adjustBrightnessFactor)
.build();
case ServiceType.DATA_SAVER:
- return builder.setBatterySaverEnabled(mEnableDataSaver)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableDataSaver)
.build();
case ServiceType.SOUND:
- return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableSoundTrigger)
.build();
case ServiceType.VIBRATION:
- return builder.setBatterySaverEnabled(mVibrationDisabledEffective)
+ return builder.setBatterySaverEnabled(mDisableVibrationEffective)
.build();
case ServiceType.FORCE_ALL_APPS_STANDBY:
- return builder.setBatterySaverEnabled(mForceAllAppsStandby)
+ return builder.setBatterySaverEnabled(mCurrPolicy.forceAllAppsStandby)
.build();
case ServiceType.FORCE_BACKGROUND_CHECK:
- return builder.setBatterySaverEnabled(mForceBackgroundCheck)
+ return builder.setBatterySaverEnabled(mCurrPolicy.forceBackgroundCheck)
.build();
case ServiceType.OPTIONAL_SENSORS:
- return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableOptionalSensors)
.build();
case ServiceType.AOD:
- return builder.setBatterySaverEnabled(mAodDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableAod)
.build();
case ServiceType.QUICK_DOZE:
- return builder.setBatterySaverEnabled(mQuickDozeEnabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableQuickDoze)
.build();
default:
return builder.setBatterySaverEnabled(realMode)
@@ -544,19 +623,20 @@
public int getGpsMode() {
synchronized (mLock) {
- return mGpsMode;
+ return mCurrPolicy.gpsMode;
}
}
public ArrayMap<String, String> getFileValues(boolean interactive) {
synchronized (mLock) {
- return interactive ? mFilesForInteractive : mFilesForNoninteractive;
+ return interactive ? mCurrPolicy.filesForInteractive
+ : mCurrPolicy.filesForNoninteractive;
}
}
public boolean isLaunchBoostDisabled() {
synchronized (mLock) {
- return mLaunchBoostDisabled;
+ return mCurrPolicy.disableLaunchBoost;
}
}
@@ -580,31 +660,35 @@
pw.println();
pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled);
- pw.println(" " + KEY_VIBRATION_DISABLED + ":config=" + mVibrationDisabledConfig);
- pw.println(" " + KEY_VIBRATION_DISABLED + ":effective=" + mVibrationDisabledEffective);
- pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
- pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
- pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
- pw.println(" " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mEnableFirewall);
- pw.println(" " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mEnableDataSaver);
- pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !mEnableAdjustBrightness);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
- pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
- pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
- pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
- pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
- pw.println(" " + KEY_AOD_DISABLED + "=" + mAodDisabled);
- pw.println(" " + KEY_QUICK_DOZE_ENABLED + "=" + mQuickDozeEnabled);
- pw.println(" " + KEY_SEND_TRON_LOG + "=" + mSendTronLog);
+ pw.println(" " + KEY_VIBRATION_DISABLED + ":config=" + mCurrPolicy.disableVibration);
+ pw.println(" " + KEY_VIBRATION_DISABLED + ":effective=" + mDisableVibrationEffective);
+ pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mCurrPolicy.disableAnimation);
+ pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mCurrPolicy.deferFullBackup);
+ pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mCurrPolicy.deferKeyValueBackup);
+ pw.println(" " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mCurrPolicy.enableFirewall);
+ pw.println(" " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mCurrPolicy.enableDataSaver);
+ pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + mCurrPolicy.disableLaunchBoost);
+ pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "="
+ + !mCurrPolicy.enableAdjustBrightness);
+ pw.println(
+ " " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mCurrPolicy.adjustBrightnessFactor);
+ pw.println(" " + KEY_GPS_MODE + "=" + mCurrPolicy.gpsMode);
+ pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mCurrPolicy.forceAllAppsStandby);
+ pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mCurrPolicy.forceBackgroundCheck);
+ pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "="
+ + mCurrPolicy.disableOptionalSensors);
+ pw.println(" " + KEY_AOD_DISABLED + "=" + mCurrPolicy.disableAod);
+ pw.println(" " + KEY_SOUNDTRIGGER_DISABLED + "=" + mCurrPolicy.disableSoundTrigger);
+ pw.println(" " + KEY_QUICK_DOZE_ENABLED + "=" + mCurrPolicy.enableQuickDoze);
+ pw.println(" " + KEY_SEND_TRON_LOG + "=" + mCurrPolicy.sendTronLog);
pw.println();
pw.print(" Interactive File values:\n");
- dumpMap(pw, " ", mFilesForInteractive);
+ dumpMap(pw, " ", mCurrPolicy.filesForInteractive);
pw.println();
pw.print(" Noninteractive File values:\n");
- dumpMap(pw, " ", mFilesForNoninteractive);
+ dumpMap(pw, " ", mCurrPolicy.filesForNoninteractive);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e65095b..6034f81 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -789,7 +789,15 @@
return startHomeOnDisplay(mCurrentUser, myReason, displayId);
}
- boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId) {
+ /**
+ * Check if home activity start should be allowed on a display.
+ * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched.
+ * @param displayId The id of the target display.
+ * @param allowInstrumenting Whether launching home should be allowed if being instrumented.
+ * @return {@code true} if allow to launch, {@code false} otherwise.
+ */
+ boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId,
+ boolean allowInstrumenting) {
if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mService.mTopAction == null) {
// We are running in factory test mode, but unable to find the factory test app, so
@@ -799,7 +807,7 @@
final WindowProcessController app =
mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid);
- if (app != null && app.isInstrumenting()) {
+ if (!allowInstrumenting && app != null && app.isInstrumenting()) {
// Don't do this if the home app is currently being instrumented.
return false;
}
@@ -2618,8 +2626,7 @@
}
ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
- getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
- return null;
+ return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
}
void resizeStackLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
@@ -4246,7 +4253,7 @@
return false;
}
- if (!canStartHomeOnDisplay(aInfo, displayId)) {
+ if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index afc946b..83db8de 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -53,6 +53,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -72,7 +73,6 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
@@ -114,9 +114,9 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.InstantAppResolver;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.wm.LaunchParamsController.LaunchParams;
-import com.android.server.pm.InstantAppResolver;
import java.io.PrintWriter;
import java.text.DateFormat;
@@ -1284,8 +1284,8 @@
// Do not start home activity if it cannot be launched on preferred display. We are not
// doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
// fallback to launch on other displays.
- if (r.isActivityTypeHome()
- && !mSupervisor.canStartHomeOnDisplay(r.info, mPreferredDisplayId)) {
+ if (r.isActivityTypeHome() && !mSupervisor.canStartHomeOnDisplay(r.info,
+ mPreferredDisplayId, true /* allowInstrumenting */)) {
Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
return START_CANCELED;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 89193f7..433c05a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6267,8 +6267,11 @@
FLAG_ACTIVITY_TASK_ON_HOME);
ActivityOptions activityOptions = options != null
? new ActivityOptions(options) : ActivityOptions.makeBasic();
- activityOptions.setLaunchTaskId(
- mStackSupervisor.getDefaultDisplayHomeActivity().getTask().taskId);
+ final ActivityRecord homeActivity =
+ mStackSupervisor.getDefaultDisplayHomeActivity();
+ if (homeActivity != null) {
+ activityOptions.setLaunchTaskId(homeActivity.getTask().taskId);
+ }
mContext.startActivityAsUser(intent, activityOptions.toBundle(),
UserHandle.CURRENT);
} finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e364e9a..933eac6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1627,7 +1627,7 @@
if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
// Start this service after all biometric services.
- traceBeginAndSlog("StartBiometricPromptService");
+ traceBeginAndSlog("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
traceEnd();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index ebac8fb..58c4bbf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,10 @@
*/
package com.android.server.pm;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -461,6 +464,7 @@
pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
pkg.requestedPermissions.add("foo7");
+ pkg.implicitPermissions.add("foo25");
pkg.protectedBroadcasts = new ArrayList<>();
pkg.protectedBroadcasts.add("foo8");
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index caaa0bb..41d5691 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -129,6 +129,7 @@
static class MyInjector extends AppStandbyController.Injector {
long mElapsedRealtime;
+ boolean mIsAppIdleEnabled = true;
boolean mIsCharging;
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
boolean mDisplayOn;
@@ -160,7 +161,7 @@
@Override
boolean isAppIdleEnabled() {
- return true;
+ return mIsAppIdleEnabled;
}
@Override
@@ -277,6 +278,13 @@
}
}
+ private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
+ mInjector.mIsAppIdleEnabled = enabled;
+ if (controller != null) {
+ controller.setAppIdleEnabled(enabled);
+ }
+ }
+
private AppStandbyController setupController() throws Exception {
mInjector.mElapsedRealtime = 0;
setupPm(mInjector.getContext().getPackageManager());
@@ -346,7 +354,7 @@
public void onParoleStateChanged(boolean isParoleOn) {
synchronized (this) {
// Only record information if it is being looked for
- if (mLatch.getCount() > 0) {
+ if (mLatch != null && mLatch.getCount() > 0) {
mOnParole = isParoleOn;
mLastParoleChangeTime = getCurrentTime();
mLatch.countDown();
@@ -407,6 +415,74 @@
marginOfError);
}
+ @Test
+ public void testEnabledState() throws Exception {
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+ long lastUpdateTime;
+
+ // Test that listeners are notified if enabled changes when the device is not in parole.
+ setChargingState(mController, false);
+
+ // Start off not enabled. Device is effectively on permanent parole.
+ setAppIdleEnabled(mController, false);
+
+ // Enable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ // Disable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+
+ // Test that listeners aren't notified if enabled status changes when the device is already
+ // in parole.
+
+ // A device is in parole whenever it's charging.
+ setChargingState(mController, true);
+
+ // Start off not enabled.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ // Test that toggling doesn't notify the listener.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+ }
+
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
mInjector.mElapsedRealtime = elapsedTime;
controller.checkIdleStates(USER_ID);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 59eab3f..9da204f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -417,6 +417,7 @@
verifyLights();
assertTrue(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -429,6 +430,7 @@
verifyNeverVibrate();
verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -439,6 +441,7 @@
verifyBeep();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -449,6 +452,7 @@
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -461,6 +465,7 @@
verifyNeverBeep();
verifyNeverVibrate();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -473,6 +478,7 @@
verifyNeverBeep();
verifyNeverVibrate();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -489,6 +495,7 @@
verifyBeepLooped();
verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -517,6 +524,7 @@
verifyNeverStopAudio();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -530,7 +538,9 @@
verifyNeverStopAudio();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
/**
@@ -567,6 +577,7 @@
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopAudio();
assertTrue(other.isInterruptive());
+ assertTrue(other.getAudiblyAlerted());
}
@Test
@@ -592,12 +603,14 @@
// set up internal state
mService.buzzBeepBlinkLocked(r);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
Mockito.reset(mRingtonePlayer);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -609,12 +622,14 @@
// set up internal state
mService.buzzBeepBlinkLocked(r);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
Mockito.reset(mRingtonePlayer);
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -631,6 +646,7 @@
verify(mService, times(1)).playInCallNotification();
verifyNeverBeep(); // doesn't play normal beep
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -650,6 +666,7 @@
eq(effect), anyString(),
(AudioAttributes) anyObject());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -667,6 +684,7 @@
verifyNeverVibrate();
verifyBeepLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -686,6 +704,7 @@
verify(mRingtonePlayer, never()).playAsync
(anyObject(), anyObject(), anyBoolean(), anyObject());
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -702,6 +721,7 @@
verifyDelayedVibrateLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -713,6 +733,7 @@
verifyNeverBeep();
verifyVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -722,6 +743,7 @@
mService.buzzBeepBlinkLocked(r);
verifyVibrateLooped();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -737,6 +759,7 @@
mService.buzzBeepBlinkLocked(r);
verifyVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -747,6 +770,7 @@
verifyNeverBeep();
assertFalse(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -759,6 +783,7 @@
verifyBeepLooped();
// summaries are never interruptive for notification counts
assertFalse(summary.isInterruptive());
+ assertTrue(summary.getAudiblyAlerted());
}
@Test
@@ -769,6 +794,7 @@
verifyBeepLooped();
assertTrue(nonGroup.isInterruptive());
+ assertTrue(nonGroup.getAudiblyAlerted());
}
@Test
@@ -780,6 +806,7 @@
verifyNeverBeep();
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -790,6 +817,7 @@
verifyBeepLooped();
assertTrue(child.isInterruptive());
+ assertTrue(child.getAudiblyAlerted());
}
@Test
@@ -800,6 +828,7 @@
verifyBeepLooped();
assertTrue(nonGroup.isInterruptive());
+ assertTrue(nonGroup.getAudiblyAlerted());
}
@Test
@@ -810,6 +839,7 @@
verifyBeepLooped();
assertTrue(group.isInterruptive());
+ assertTrue(group.getAudiblyAlerted());
}
@Test
@@ -822,11 +852,13 @@
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
// update should not beep
mService.buzzBeepBlinkLocked(s);
verifyNeverVibrate();
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -839,6 +871,7 @@
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
}
@Test
@@ -852,7 +885,9 @@
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -871,8 +906,11 @@
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertTrue(other.isInterruptive());
+ assertTrue(other.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -888,6 +926,7 @@
mService.buzzBeepBlinkLocked(other);
verifyNeverStopVibrate();
assertFalse(other.isInterruptive());
+ assertFalse(other.getAudiblyAlerted());
}
@Test
@@ -904,7 +943,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -921,7 +962,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -939,7 +982,9 @@
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
assertTrue(r.isInterruptive());
+ assertTrue(r.getAudiblyAlerted());
assertFalse(s.isInterruptive());
+ assertFalse(s.getAudiblyAlerted());
}
@Test
@@ -957,6 +1002,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -968,6 +1014,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1010,6 +1057,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1043,6 +1091,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1052,6 +1101,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1060,6 +1110,7 @@
mService.buzzBeepBlinkLocked(r);
verifyLights();
assertTrue(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
r = getLightsOnceNotification();
r.isUpdate = true;
@@ -1067,6 +1118,7 @@
// checks that lights happened once, i.e. this new call didn't trigger them again
verifyLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1076,6 +1128,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1084,6 +1137,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1093,6 +1147,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1102,6 +1157,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1111,6 +1167,7 @@
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
+ assertFalse(r.getAudiblyAlerted());
}
@Test
@@ -1121,6 +1178,7 @@
verifyNeverLights();
assertFalse(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -1133,6 +1191,7 @@
verifyLights();
// summaries should never count for interruptiveness counts
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -1143,6 +1202,7 @@
verifyLights();
assertTrue(nonGroup.isInterruptive());
+ assertFalse(nonGroup.getAudiblyAlerted());
}
@Test
@@ -1154,6 +1214,7 @@
verifyNeverLights();
assertFalse(summary.isInterruptive());
+ assertFalse(summary.getAudiblyAlerted());
}
@Test
@@ -1164,6 +1225,7 @@
verifyLights();
assertTrue(child.isInterruptive());
+ assertFalse(child.getAudiblyAlerted());
}
@Test
@@ -1174,6 +1236,7 @@
verifyLights();
assertTrue(nonGroup.isInterruptive());
+ assertFalse(nonGroup.getAudiblyAlerted());
}
@Test
@@ -1184,6 +1247,7 @@
verifyLights();
assertTrue(group.isInterruptive());
+ assertFalse(group.getAudiblyAlerted());
}
static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index f255d49..0d7b584 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -38,12 +38,10 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.Parcel;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -94,6 +92,7 @@
assertEquals(getShowBadge(i), ranking.canShowBadge());
assertEquals(getUserSentiment(i), ranking.getUserSentiment());
assertEquals(getHidden(i), ranking.isSuspended());
+ assertEquals(audiblyAlerted(i), ranking.audiblyAlerted());
assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
}
@@ -114,6 +113,7 @@
Bundle mHidden = new Bundle();
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
+ Bundle audiblyAlerted = new Bundle();
for (int i = 0; i < mKeys.length; i++) {
String key = mKeys[i];
@@ -133,12 +133,13 @@
mHidden.putBoolean(key, getHidden(i));
smartActions.putParcelableArrayList(key, getSmartActions(key, i));
smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
+ audiblyAlerted.putBoolean(key, audiblyAlerted(i));
}
NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
interceptedKeys.toArray(new String[0]), visibilityOverrides,
suppressedVisualEffects, importance, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
- smartActions, smartReplies);
+ smartActions, smartReplies, audiblyAlerted);
return update;
}
@@ -190,6 +191,10 @@
return index % 2 == 0;
}
+ private boolean audiblyAlerted(int index) {
+ return index < 2;
+ }
+
private ArrayList<String> getPeople(String key, int index) {
ArrayList<String> people = new ArrayList<>();
for (int i = 0; i < index; i++) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 1b59e75..9b41fdd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -801,4 +801,16 @@
assertEquals(1.0f, record.getContactAffinity());
assertEquals(IMPORTANCE_LOW, record.getImportance());
}
+
+ @Test
+ public void testSetAudiblyAlerted() {
+ StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ record.setAudiblyAlerted(true);
+
+ assertTrue(record.getAudiblyAlerted());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index c2ef478..f692a57 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -25,12 +25,12 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -54,6 +54,8 @@
import android.app.ActivityOptions;
import android.app.WaitResult;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -436,7 +438,7 @@
* Tests that home activities can be started on the displays that supports system decorations.
*/
@Test
- public void testStartHomeOnAllDisplays() throws Exception {
+ public void testStartHomeOnAllDisplays() {
// Create secondary displays.
final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
mSupervisor.addChild(secondDisplay, POSITION_TOP);
@@ -450,7 +452,7 @@
.create(any(), anyInt(), any(), any(), any(), any());
doReturn(true).when(mService.mStackSupervisor)
.ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
- doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt());
+ doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt(), anyBoolean());
mSupervisor.startHomeOnAllDisplays(0, "testStartHome");
@@ -463,7 +465,7 @@
* Tests that home activities won't be started before booting when display added.
*/
@Test
- public void testNotStartHomeBeforeBoot() throws Exception {
+ public void testNotStartHomeBeforeBoot() {
final int displayId = 1;
final boolean isBooting = mService.mAmInternal.isBooting();
final boolean isBooted = mService.mAmInternal.isBooted();
@@ -477,4 +479,30 @@
mService.mAmInternal.setBooted(isBooted);
}
}
+
+ /**
+ * Tests whether home can be started if being instrumented.
+ */
+ @Test
+ public void testCanStartHomeWhenInstrumented() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ final WindowProcessController app = mock(WindowProcessController.class);
+ doReturn(app).when(mService).getProcessController(any(), anyInt());
+
+ // Can not start home if we don't want to start home while home is being instrumented.
+ doReturn(true).when(app).isInstrumenting();
+ assertFalse(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ false /* allowInstrumenting*/));
+
+ // Can start home for other cases.
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ true /* allowInstrumenting*/));
+
+ doReturn(false).when(app).isInstrumenting();
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ false /* allowInstrumenting*/));
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ true /* allowInstrumenting*/));
+ }
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 6a74564..4f573a4 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,18 +30,19 @@
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
@@ -340,14 +341,21 @@
}
void setAppIdleEnabled(boolean enabled) {
- mAppIdleEnabled = enabled;
+ synchronized (mAppIdleLock) {
+ if (mAppIdleEnabled != enabled) {
+ final boolean oldParoleState = isParoledOrCharging();
+ mAppIdleEnabled = enabled;
+ if (isParoledOrCharging() != oldParoleState) {
+ postParoleStateChanged();
+ }
+ }
+ }
}
public void onBootPhase(int phase) {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
Slog.d(TAG, "Setting app idle enabled state");
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Observe changes to the threshold
SettingsObserver settingsObserver = new SettingsObserver(mHandler);
settingsObserver.registerObserver();
@@ -1842,8 +1850,6 @@
mContext.getContentResolver(),
Global.APP_IDLE_CONSTANTS));
}
- // Check if app_idle_enabled has changed
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Look at global settings for this.
// TODO: Maybe apply different thresholds for different users.
@@ -1915,6 +1921,10 @@
(KEY_STABLE_CHARGING_THRESHOLD,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
}
+
+ // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
+ // in case we need to change something based on the new values.
+ setAppIdleEnabled(mInjector.isAppIdleEnabled());
}
long[] parseLongArray(String values, long[] defaults) {
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index f62b170..7db6940 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
@@ -229,7 +230,8 @@
callDetails.getTelecomCallId(),
response.getRejectCall(),
!response.getSkipCallLog(),
- !response.getSkipNotification());
+ !response.getSkipNotification(),
+ new ComponentName(getPackageName(), getClass().getName()));
} else {
mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index 2e0af27..d255ed1 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -16,6 +16,8 @@
package com.android.internal.telecom;
+import android.content.ComponentName;
+
/**
* Internal remote callback interface for call screening services.
*
@@ -30,5 +32,6 @@
String callId,
boolean shouldReject,
boolean shouldAddToCallLog,
- boolean shouldShowNotification);
+ boolean shouldShowNotification,
+ in ComponentName componentName);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 99de4ca..3f9a533 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1257,20 +1257,11 @@
public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
/**
- * Package name of the carrier settings activity.
- * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING}.
+ * Flatten {@link android.content.ComponentName} of the carrier's settings activity.
* @hide
*/
- public static final String KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING =
- "carrier_settings_activity_package_name_string";
-
- /**
- * Class name of the carrier settings activity.
- * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING}.
- * @hide
- */
- public static final String KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING =
- "carrier_settings_activity_class_name_string";
+ public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
+ "carrier_settings_activity_component_name_string";
// These variables are used by the MMS service and exposed through another API,
// SmsManager. The variable names and string values are copied from there.
@@ -2615,8 +2606,7 @@
sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_WORLD_MODE_ENABLED_BOOL, false);
- sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING, "");
- sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING, "");
+ sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING, "");
sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 76a0026..6958d22 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -190,6 +190,7 @@
case CellInfo.TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
case CellInfo.TYPE_TDSCDMA:
return CellIdentityTdscdma.createFromParcelBody(in);
+ case CellInfo.TYPE_NR: return CellIdentityNr.createFromParcelBody(in);
default: throw new IllegalArgumentException("Bad Cell identity Parcel");
}
}
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
new file mode 100644
index 0000000..6b1b84c
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -0,0 +1,167 @@
+/*
+ * 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.telephony;
+
+import android.os.Parcel;
+import android.telephony.gsm.GsmCellLocation;
+
+import java.util.Objects;
+
+/**
+ * Information to represent a unique 5G NR cell.
+ */
+public final class CellIdentityNr extends CellIdentity {
+ private static final String TAG = "CellIdentityNr";
+
+ private final int mNrArfcn;
+ private final int mPci;
+ private final int mTac;
+
+ /**
+ *
+ * @param pci Physical Cell Id in range [0, 1007].
+ * @param tac 16-bit Tracking Area Code.
+ * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
+ * @param mccStr 3-digit Mobile Country Code in string format.
+ * @param mncStr 2 or 3-digit Mobile Network Code in string format.
+ * @param alphal long alpha Operator Name String or Enhanced Operator Name String.
+ * @param alphas short alpha Operator Name String or Enhanced Operator Name String.
+ *
+ * @hide
+ */
+ public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
+ String alphal, String alphas) {
+ super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
+ mPci = pci;
+ mTac = tac;
+ mNrArfcn = nrArfcn;
+ }
+
+ /**
+ * @return a CellLocation object for this CellIdentity.
+ * @hide
+ */
+ @Override
+ public CellLocation asCellLocation() {
+ return new GsmCellLocation();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CellIdentityNr)) {
+ return false;
+ }
+
+ CellIdentityNr o = (CellIdentityNr) other;
+ return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn;
+ }
+
+ /**
+ * Get the Absolute Radio Frequency Channel Number.
+ * @return Integer value in range [0, 3279165] or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ @Override
+ public int getChannelNumber() {
+ return mNrArfcn;
+ }
+
+ /**
+ * Get the physical cell id.
+ * @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ public int getPci() {
+ return mPci;
+ }
+
+ /**
+ * Get the tracking area code.
+ * @return a 16 bit integer or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ public int getTac() {
+ return mTac;
+ }
+
+ /**
+ * @return Mobile Country Code in string format, or {@code null} if unknown.
+ */
+ public String getMccString() {
+ return mMccStr;
+ }
+
+ /**
+ * @return Mobile Network Code in string fomrat, or {@code null} if unknown.
+ */
+ public String getMncString() {
+ return mMncStr;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(TAG + ":{")
+ .append(" mPci = ").append(mPci)
+ .append(" mTac = ").append(mTac)
+ .append(" mNrArfcn = ").append(mNrArfcn)
+ .append(" mMcc = ").append(mMccStr)
+ .append(" mMnc = ").append(mMncStr)
+ .append(" mAlphaLong = ").append(mAlphaLong)
+ .append(" mAlphaShort = ").append(mAlphaShort)
+ .append(" }")
+ .toString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int type) {
+ super.writeToParcel(dest, CellInfo.TYPE_NR);
+ dest.writeInt(mPci);
+ dest.writeInt(mTac);
+ dest.writeInt(mNrArfcn);
+ }
+
+ /** Construct from Parcel, type has already been processed */
+ private CellIdentityNr(Parcel in) {
+ super(TAG, CellInfo.TYPE_NR, in);
+ mPci = in.readInt();
+ mTac = in.readInt();
+ mNrArfcn = in.readInt();
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<CellIdentityNr> CREATOR =
+ new Creator<CellIdentityNr>() {
+ @Override
+ public CellIdentityNr createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
+ return createFromParcelBody(in);
+ }
+
+ @Override
+ public CellIdentityNr[] newArray(int size) {
+ return new CellIdentityNr[size];
+ }
+ };
+
+ /** @hide */
+ protected static CellIdentityNr createFromParcelBody(Parcel in) {
+ return new CellIdentityNr(in);
+ }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 1c63e82..d0b2687 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -42,38 +42,51 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "TYPE_", value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA})
+ @IntDef(prefix = "TYPE_",
+ value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA, TYPE_NR})
public @interface Type {}
+
/**
* Unknown cell identity type
* @hide
*/
- public static final int TYPE_UNKNOWN = 0;
+ public static final int TYPE_UNKNOWN = 0;
+
/**
* GSM cell identity type
* @hide
*/
- public static final int TYPE_GSM = 1;
+ public static final int TYPE_GSM = 1;
+
/**
* CDMA cell identity type
* @hide
*/
- public static final int TYPE_CDMA = 2;
+ public static final int TYPE_CDMA = 2;
+
/**
* LTE cell identity type
* @hide
*/
- public static final int TYPE_LTE = 3;
+ public static final int TYPE_LTE = 3;
+
/**
* WCDMA cell identity type
* @hide
*/
- public static final int TYPE_WCDMA = 4;
+ public static final int TYPE_WCDMA = 4;
+
/**
* TD-SCDMA cell identity type
* @hide
*/
- public static final int TYPE_TDSCDMA = 5;
+ public static final int TYPE_TDSCDMA = 5;
+
+ /**
+ * 5G cell identity type
+ * @hide
+ */
+ public static final int TYPE_NR = 6;
// Type to distinguish where time stamp gets recorded.
@@ -277,6 +290,7 @@
case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
case TYPE_TDSCDMA: return CellInfoTdscdma.createFromParcelBody(in);
+ case TYPE_NR: return CellInfoNr.createFromParcelBody(in);
default: throw new RuntimeException("Bad CellInfo Parcel");
}
}
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
new file mode 100644
index 0000000..11857a6
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -0,0 +1,100 @@
+/*
+ * 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.telephony;
+
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * A {@link CellInfo} representing an 5G NR cell that provides identity and measurement info.
+ */
+public final class CellInfoNr extends CellInfo {
+ private static final String TAG = "CellInfoNr";
+
+ private final CellIdentityNr mCellIdentity;
+ private final CellSignalStrengthNr mCellSignalStrength;
+
+ private CellInfoNr(Parcel in) {
+ super(in);
+ mCellIdentity = CellIdentityNr.CREATOR.createFromParcel(in);
+ mCellSignalStrength = CellSignalStrengthNr.CREATOR.createFromParcel(in);
+ }
+
+ @Override
+ public CellIdentity getCellIdentity() {
+ return mCellIdentity;
+ }
+
+ @Override
+ public CellSignalStrength getCellSignalStrength() {
+ return mCellSignalStrength;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mCellIdentity, mCellSignalStrength);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CellInfoNr)) {
+ return false;
+ }
+
+ CellInfoNr o = (CellInfoNr) other;
+ return super.equals(o) && mCellIdentity.equals(o.mCellIdentity)
+ && mCellSignalStrength.equals(o.mCellSignalStrength);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append(TAG + ":{")
+ .append(" " + super.toString())
+ .append(" " + mCellIdentity)
+ .append(" " + mCellSignalStrength)
+ .append(" }")
+ .toString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags, TYPE_NR);
+ mCellIdentity.writeToParcel(dest, flags);
+ mCellSignalStrength.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<CellInfoNr> CREATOR = new Creator<CellInfoNr>() {
+ @Override
+ public CellInfoNr createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
+ return new CellInfoNr(in);
+ }
+
+ @Override
+ public CellInfoNr[] newArray(int size) {
+ return new CellInfoNr[size];
+ }
+ };
+
+ /** @hide */
+ protected static CellInfoNr createFromParcelBody(Parcel in) {
+ return new CellInfoNr(in);
+ }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index d6856b3..2ff75e6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -19,7 +19,6 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
import java.util.Objects;
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
new file mode 100644
index 0000000..8079242
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -0,0 +1,257 @@
+/*
+ * 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * 5G NR signal strength related information.
+ */
+public final class CellSignalStrengthNr extends CellSignalStrength implements Parcelable {
+ /**
+ * The value is used to indicate that the asu level is unknown.
+ * Reference: 3GPP TS 27.007 section 8.69.
+ * @hide
+ */
+ public static final int UNKNOWN_ASU_LEVEL = 99;
+
+ private static final String TAG = "CellSignalStrengthNr";
+
+ /**
+ * These threshold values are copied from LTE.
+ * TODO: make it configurable via CarrierConfig.
+ */
+ private static final int SIGNAL_GREAT_THRESHOLD = -95;
+ private static final int SIGNAL_GOOD_THRESHOLD = -105;
+ private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+
+ private int mCsiRsrp;
+ private int mCsiRsrq;
+ private int mCsiSinr;
+ private int mSsRsrp;
+ private int mSsRsrq;
+ private int mSsSinr;
+
+ /**
+ * @param csiRsrp CSI reference signal received power.
+ * @param csiRsrq CSI reference signal received quality.
+ * @param csiSinr CSI signal-to-noise and interference ratio.
+ * @param ssRsrp SS reference signal received power.
+ * @param ssRsrq SS reference signal received quality.
+ * @param ssSinr SS signal-to-noise and interference ratio.
+ * @hide
+ */
+ public CellSignalStrengthNr(
+ int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
+ mCsiRsrp = csiRsrp;
+ mCsiRsrq = csiRsrq;
+ mCsiSinr = csiSinr;
+ mSsRsrp = ssRsrp;
+ mSsRsrq = ssRsrq;
+ mSsSinr = ssSinr;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -140 dBm to -44 dBm.
+ * @return SS reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getSsRsrp() {
+ return mSsRsrp;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -20 dB to -3 dB.
+ * @return SS reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getSsRsrq() {
+ return mSsRsrq;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+ * Range: -23 dB to 40 dB
+ * @return SS signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+ * unreported value.
+ */
+ public int getSsSinr() {
+ return mSsSinr;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -140 dBm to -44 dBm.
+ * @return CSI reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getCsiRsrp() {
+ return mCsiRsrp;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -20 dB to -3 dB.
+ * @return CSI reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getCsiRsrq() {
+ return mCsiRsrq;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+ * Range: -23 dB to 23 dB
+ * @return CSI signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+ * unreported value.
+ */
+ public int getCsiSinr() {
+ return mCsiSinr;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCsiRsrp);
+ dest.writeInt(mCsiRsrq);
+ dest.writeInt(mCsiSinr);
+ dest.writeInt(mSsRsrp);
+ dest.writeInt(mSsRsrq);
+ dest.writeInt(mSsSinr);
+ }
+
+ private CellSignalStrengthNr(Parcel in) {
+ mCsiRsrp = in.readInt();
+ mCsiRsrq = in.readInt();
+ mCsiSinr = in.readInt();
+ mSsRsrp = in.readInt();
+ mSsRsrq = in.readInt();
+ mSsSinr = in.readInt();
+ }
+
+ /** @hide */
+ @Override
+ public void setDefaultValues() {
+ mCsiRsrp = CellInfo.UNAVAILABLE;
+ mCsiRsrq = CellInfo.UNAVAILABLE;
+ mCsiSinr = CellInfo.UNAVAILABLE;
+ mSsRsrp = CellInfo.UNAVAILABLE;
+ mSsRsrq = CellInfo.UNAVAILABLE;
+ mSsSinr = CellInfo.UNAVAILABLE;
+ }
+
+ @Override
+ public int getLevel() {
+ if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+ return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+ return SIGNAL_STRENGTH_GREAT;
+ } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+ return SIGNAL_STRENGTH_GOOD;
+ } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+ return SIGNAL_STRENGTH_MODERATE;
+ } else {
+ return SIGNAL_STRENGTH_POOR;
+ }
+ }
+
+ /**
+ * Calculates the NR signal as an asu value between 0..97, 99 is unknown.
+ * Asu is calculated based on 3GPP RSRP, refer to 3GPP TS 27.007 section 8.69.
+ * @return an integer represent the asu level of the signal strength.
+ */
+ @Override
+ public int getAsuLevel() {
+ int asuLevel;
+ int nrDbm = getDbm();
+ if (nrDbm == CellInfo.UNAVAILABLE) {
+ asuLevel = UNKNOWN_ASU_LEVEL;
+ } else if (nrDbm <= -140) {
+ asuLevel = 0;
+ } else if (nrDbm >= -43) {
+ asuLevel = 97;
+ } else {
+ asuLevel = nrDbm + 140;
+ }
+ return asuLevel;
+ }
+
+ @Override
+ public int getDbm() {
+ return mCsiRsrp;
+ }
+
+ /** @hide */
+ @Override
+ public CellSignalStrength copy() {
+ return new CellSignalStrengthNr(
+ mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CellSignalStrengthNr) {
+ CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
+ return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
+ && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append(TAG + ":{")
+ .append(" csiRsrp = " + mCsiRsrp)
+ .append(" csiRsrq = " + mCsiRsrq)
+ .append(" csiSinr = " + mCsiSinr)
+ .append(" ssRsrp = " + mSsRsrp)
+ .append(" ssRsrq = " + mSsRsrq)
+ .append(" ssSinr = " + mSsSinr)
+ .append(" }")
+ .toString();
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<CellSignalStrengthNr> CREATOR =
+ new Parcelable.Creator<CellSignalStrengthNr>() {
+ @Override
+ public CellSignalStrengthNr createFromParcel(Parcel in) {
+ return new CellSignalStrengthNr(in);
+ }
+
+ @Override
+ public CellSignalStrengthNr[] newArray(int size) {
+ return new CellSignalStrengthNr[size];
+ }
+ };
+}
diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
index 95f39d7..d07d77c 100644
--- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java
+++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.CellInfo;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -106,6 +107,17 @@
}
@Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{")
+ .append("scanStatus=" + scanStatus)
+ .append(", scanError=" + scanError)
+ .append(", networkInfos=" + networkInfos)
+ .append("}")
+ .toString();
+ }
+
+ @Override
public int hashCode () {
return ((scanStatus * 31)
+ (scanError * 23)
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 414758e..2e717ff 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -248,6 +248,7 @@
if (!split_entry->id) {
split_entry->id = entry->id;
split_entry->visibility = entry->visibility;
+ split_entry->overlayable_declarations = entry->overlayable_declarations;
}
// Copy the selected values into the new Split Entry.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 5a4c898..e6892be 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -16,9 +16,13 @@
package android.net.wifi.p2p;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
-import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.wifi.WpsInfo;
@@ -480,6 +484,12 @@
/** @hide */
public static final int REPORT_NFC_HANDOVER_FAILED = BASE + 81;
+ /** @hide */
+ public static final int FACTORY_RESET = BASE + 82;
+ /** @hide */
+ public static final int FACTORY_RESET_FAILED = BASE + 83;
+ /** @hide */
+ public static final int FACTORY_RESET_SUCCEEDED = BASE + 84;
/**
* Create a new WifiP2pManager instance. Applications use
@@ -776,6 +786,7 @@
case STOP_LISTEN_FAILED:
case SET_CHANNEL_FAILED:
case REPORT_NFC_HANDOVER_FAILED:
+ case FACTORY_RESET_FAILED:
if (listener != null) {
((ActionListener) listener).onFailure(message.arg1);
}
@@ -802,6 +813,7 @@
case STOP_LISTEN_SUCCEEDED:
case SET_CHANNEL_SUCCEEDED:
case REPORT_NFC_HANDOVER_SUCCEEDED:
+ case FACTORY_RESET_SUCCEEDED:
if (listener != null) {
((ActionListener) listener).onSuccess();
}
@@ -1521,4 +1533,21 @@
c.mAsyncChannel.sendMessage(RESPONDER_REPORT_NFC_HANDOVER, 0,
c.putListener(listener), bundle);
}
+
+ /**
+ * Removes all saved p2p groups.
+ * @param c is the channel created at {@link #initialize}.
+ * @param listener for callback on success or failure. Can be null.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void factoryReset(@NonNull Channel c, @Nullable ActionListener listener) {
+ checkChannel(c);
+ Bundle callingPackage = new Bundle();
+ callingPackage.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
+ c.mAsyncChannel.sendMessage(FACTORY_RESET, 0, c.putListener(listener),
+ callingPackage);
+ }
+
}
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
new file mode 100644
index 0000000..eede23b
--- /dev/null
+++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java
@@ -0,0 +1,415 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License") {
+ * throw new UnsupportedOperationException();
+ }
+ * 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.wifi;
+
+import android.content.pm.ParceledListSlice;
+import android.net.DhcpInfo;
+import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.ISoftApCallback;
+import android.net.wifi.ITrafficStateCallback;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.PasspointManagementObjectDefinition;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.os.IBinder;
+import android.os.Messenger;
+import android.os.ResultReceiver;
+import android.os.WorkSource;
+import android.util.Slog;
+
+import java.util.List;
+
+/**
+ * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions.
+ *
+ * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
+ * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
+ * deprecated APIs, or the migration of existing API signatures.
+ *
+ * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
+ * immediately and marked as @Deprecated first in this class. Children inheriting this class are
+ * then given a short grace period to update themselves before the @Deprecated stub is removed for
+ * good. If the API scheduled for removal has a replacement or an overload (signature change),
+ * these should be introduced before the stub is removed to allow children to migrate.
+ */
+public abstract class AbstractWifiService extends IWifiManager.Stub {
+
+ private static final String TAG = AbstractWifiService.class.getSimpleName();
+
+ @Override
+ public int getSupportedFeatures() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WifiActivityEnergyInfo reportActivityInfo() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void requestActivityInfo(ResultReceiver result) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ParceledListSlice getConfiguredNetworks() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ParceledListSlice getPrivilegedConfiguredNetworks() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addOrUpdatePasspointConfiguration(
+ PasspointConfiguration config, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removePasspointConfiguration(String fqdn, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<PasspointConfiguration> getPasspointConfigurations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void queryPasspointIcon(long bssid, String fileName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int matchProviderWithCurrentNetwork(String fqdn) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void deauthenticateNetwork(long holdoff, boolean ess) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeNetwork(int netId, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean disableNetwork(int netId, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean startScan(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<ScanResult> getScanResults(String callingPackage) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void disconnect(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void reconnect(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void reassociate(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WifiInfo getConnectionInfo(String callingPackage) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean setWifiEnabled(String packageName, boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getWifiEnabledState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setCountryCode(String country) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCountryCode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isDualBandSupported() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean needs5GHzToAnyApBandConversion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DhcpInfo getDhcpInfo() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isScanAlwaysAvailable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean releaseWifiLock(IBinder lock) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void initializeMulticastFiltering() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMulticastEnabled() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void acquireMulticastLock(IBinder binder, String tag) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void releaseMulticastLock(String tag) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void updateInterfaceIpState(String ifaceName, int mode) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean startSoftAp(WifiConfiguration wifiConfig) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean stopSoftAp() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void stopLocalOnlyHotspot() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void stopWatchLocalOnlyHotspot() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getWifiApEnabledState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public WifiConfiguration getWifiApConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void notifyUserOfApBandConversion(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Messenger getWifiServiceMessenger(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void enableTdls(String remoteIPAddress, boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCurrentNetworkWpsNfcConfigurationToken() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void enableVerboseLogging(int verbose) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getVerboseLoggingLevel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void enableWifiConnectivityManager(boolean enabled) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void disableEphemeralNetwork(String SSID, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void factoryReset(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Network getCurrentNetwork() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] retrieveBackupData() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void restoreBackupData(byte[] data) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startSubscriptionProvisioning(
+ OsuProvider provider, IProvisioningCallback callback) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerSoftApCallback(
+ IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterSoftApCallback(int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerTrafficStateCallback(
+ IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterTrafficStateCallback(int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerNetworkRequestMatchCallback(
+ IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
+ throw new UnsupportedOperationException();
+ }
+}