Merge "API Rename: IC#inputContent to IC#commitContent." into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 7088764..a69f503 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -420,9 +420,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1041,7 +1041,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1109,20 +1109,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -10099,14 +10095,14 @@
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9b1b765..e30c247 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -527,9 +527,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1148,7 +1148,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1220,20 +1220,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -10523,14 +10519,14 @@
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index d0d84ec..480d8dc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -420,9 +420,9 @@
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
- field public static final int contextDescription = 16844082; // 0x1010532
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
- field public static final int contextUri = 16844081; // 0x1010531
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1041,7 +1041,7 @@
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int roundIcon = 16844080; // 0x1010530
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1109,20 +1109,16 @@
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
- field public static final int shortcutCategories = 16844077; // 0x101052d
- field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
- field public static final int shortcutIcon = 16844073; // 0x1010529
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
field public static final int shortcutId = 16844072; // 0x1010528
- field public static final int shortcutIntentAction = 16844078; // 0x101052e
- field public static final int shortcutIntentData = 16844079; // 0x101052f
- field public static final int shortcutLongLabel = 16844075; // 0x101052b
- field public static final int shortcutShortLabel = 16844074; // 0x101052a
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
- field public static final int showMetadataInPreview = 16844083; // 0x1010533
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -10112,14 +10108,14 @@
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
- method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
- method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
- method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
}
public class ShortcutManager {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f12c284..3c7eef5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1779,9 +1779,10 @@
case START_BACKUP_AGENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data);
+ String packageName = data.readString();
int backupRestoreMode = data.readInt();
- boolean success = bindBackupAgent(info, backupRestoreMode);
+ int userId = data.readInt();
+ boolean success = bindBackupAgent(packageName, backupRestoreMode, userId);
reply.writeNoException();
reply.writeInt(success ? 1 : 0);
return true;
@@ -4448,13 +4449,14 @@
return binder;
}
- public boolean bindBackupAgent(ApplicationInfo app, int backupRestoreMode)
+ public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- app.writeToParcel(data, 0);
+ data.writeString(packageName);
data.writeInt(backupRestoreMode);
+ data.writeInt(userId);
mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0);
reply.readException();
boolean success = reply.readInt() != 0;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 81788da..ac21346 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@
public IBinder peekService(Intent service, String resolvedType, String callingPackage)
throws RemoteException;
- public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
+ public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId)
throws RemoteException;
public void clearPendingBackup() throws RemoteException;
public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 896fa43..064b909 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -30,6 +30,7 @@
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -245,7 +246,7 @@
mTextResId = b.mTextResId;
mDisabledMessage = b.mDisabledMessage;
mDisabledMessageResId = b.mDisabledMessageResId;
- mCategories = clone(b.mCategories);
+ mCategories = cloneCategories(b.mCategories);
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -259,8 +260,17 @@
updateTimestamp();
}
- private <T> ArraySet<T> clone(Set<T> source) {
- return (source == null) ? null : new ArraySet<>(source);
+ private ArraySet<String> cloneCategories(Set<String> source) {
+ if (source == null) {
+ return null;
+ }
+ final ArraySet<String> ret = new ArraySet<>(source.size());
+ for (CharSequence s : source) {
+ if (!TextUtils.isEmpty(s)) {
+ ret.add(s.toString().intern());
+ }
+ }
+ return ret;
}
/**
@@ -304,7 +314,7 @@
mTextResId = source.mTextResId;
mDisabledMessage = source.mDisabledMessage;
mDisabledMessageResId = source.mDisabledMessageResId;
- mCategories = clone(source.mCategories);
+ mCategories = cloneCategories(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -614,7 +624,7 @@
mDisabledMessageResName = null;
}
if (source.mCategories != null) {
- mCategories = clone(source.mCategories);
+ mCategories = cloneCategories(source.mCategories);
}
if (source.mIntent != null) {
mIntent = source.mIntent;
@@ -752,7 +762,7 @@
* an icon. The recommend max length is 10 characters.
*/
@NonNull
- public Builder setShortLabel(@NonNull String shortLabel) {
+ public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel");
return this;
@@ -776,14 +786,14 @@
* The recommend max length is 25 characters.
*/
@NonNull
- public Builder setLongLabel(@NonNull String longLabel) {
+ public Builder setLongLabel(@NonNull CharSequence longLabel) {
Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel");
return this;
}
/** @hide -- old signature, the internal code still uses it. */
- public Builder setTitle(@NonNull String value) {
+ public Builder setTitle(@NonNull CharSequence value) {
return setShortLabel(value);
}
@@ -793,7 +803,7 @@
}
/** @hide -- old signature, the internal code still uses it. */
- public Builder setText(@NonNull String value) {
+ public Builder setText(@NonNull CharSequence value) {
return setLongLabel(value);
}
@@ -813,7 +823,7 @@
}
@NonNull
- public Builder setDisabledMessage(@NonNull String disabledMessage) {
+ public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Preconditions.checkState(
mDisabledMessageResId == 0, "disabledMessageResId already set");
mDisabledMessage =
@@ -1355,6 +1365,37 @@
mIconResName = iconResName;
}
+ /**
+ * Replaces the intent
+ *
+ * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
+ *
+ * @hide
+ */
+ public void setIntent(Intent intent) throws IllegalArgumentException {
+ Preconditions.checkNotNull(intent);
+
+ final Bundle intentExtras = intent.getExtras();
+
+ mIntent = intent;
+
+ if (intentExtras != null) {
+ intent.replaceExtras((Bundle) null);
+ mIntentPersistableExtras = new PersistableBundle(intentExtras);
+ } else {
+ mIntentPersistableExtras = null;
+ }
+ }
+
+ /**
+ * Replaces the categories.
+ *
+ * @hide
+ */
+ public void setCategories(Set<String> categories) {
+ mCategories = cloneCategories(categories);
+ }
+
private ShortcutInfo(Parcel source) {
final ClassLoader cl = getClass().getClassLoader();
@@ -1591,7 +1632,7 @@
mDisabledMessage = disabledMessage;
mDisabledMessageResId = disabledMessageResId;
mDisabledMessageResName = disabledMessageResName;
- mCategories = clone(categories);
+ mCategories = cloneCategories(categories);
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mRank = rank;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d59c8ac..17834fb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -464,7 +464,8 @@
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
getLocationInWindow(mLocation);
- if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
@@ -534,7 +535,8 @@
mReportDrawNeeded = false;
mDrawingStopped = !visible;
- if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Cur surface: " + mSurface);
relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
@@ -547,7 +549,8 @@
reportDrawNeeded = true;
}
- if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "New surface: " + mNewSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
@@ -581,7 +584,8 @@
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
- if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
@@ -594,7 +598,8 @@
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
- if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "visibleChanged -- surfaceCreated");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
@@ -604,7 +609,8 @@
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
- if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "surfaceChanged -- format=" + mFormat
+ " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
@@ -614,7 +620,8 @@
}
}
if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "surfaceRedrawNeeded");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
@@ -629,7 +636,8 @@
} finally {
mIsCreating = false;
if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, "finishedDrawing");
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "finishedDrawing");
mSession.finishDrawing(mWindow);
}
mSession.performDeferredDestroy(mWindow);
@@ -663,8 +671,9 @@
}
try {
- Log.d(TAG, String.format("updateWindowPosition UI, " +
- "postion = [%d, %d, %d, %d]", mWinFrame.left, mWinFrame.top,
+ Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+ "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+ mWinFrame.left, mWinFrame.top,
mWinFrame.right, mWinFrame.bottom));
mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
@@ -697,9 +706,9 @@
}
try {
if (DEBUG) {
- Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " +
- "postion = [%d, %d, %d, %d]", frameNumber, left, top,
- right, bottom));
+ Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
+ "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
+ frameNumber, left, top, right, bottom));
}
// Just using mRTLastReportedPosition as a dummy rect here
session.repositionChild(window, left, top, right, bottom,
@@ -712,6 +721,25 @@
}
}
+ /**
+ * Called by native on RenderThread to notify that the window is no longer in the
+ * draw tree
+ * @hide
+ */
+ public final void windowPositionLostRT(long frameNumber) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
+ System.identityHashCode(this), frameNumber));
+ }
+ // TODO: This is a bit of a hack as we don't have an API to report to WM
+ // to hide a window with a frameNumber, so just shift the window very far into
+ // negative space which will do effectively the same thing.
+ // Use the last reported size to avoid influencing the size of the bufferqueue
+ int x = -1000 - mRTLastReportedPosition.width();
+ int y = -1000 - mRTLastReportedPosition.height();
+ updateWindowPositionRT(frameNumber, x, y, -1000, -1000);
+ }
+
private SurfaceHolder.Callback[] getSurfaceCallbacks() {
SurfaceHolder.Callback callbacks[];
synchronized (mCallbacks) {
@@ -750,8 +778,7 @@
boolean alwaysConsumeNavBar) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
- if (DEBUG) Log.v(
- "SurfaceView", surfaceView + " got resized: w=" + frame.width()
+ if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
+ " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
surfaceView.mSurfaceLock.lock();
try {
@@ -907,7 +934,7 @@
private final Canvas internalLockCanvas(Rect dirty) {
mSurfaceLock.lock();
- if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow);
Canvas c = null;
@@ -919,7 +946,7 @@
}
}
- if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Returned canvas: " + c);
if (c != null) {
mLastLockTime = SystemClock.uptimeMillis();
return c;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a6db0f4..4fc546c 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -534,6 +534,7 @@
// ----------------------------------------------------------------------------
jmethodID gSurfaceViewPositionUpdateMethod;
+jmethodID gSurfaceViewPositionLostMethod;
static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
jlong renderNodePtr, jobject surfaceview) {
@@ -581,6 +582,20 @@
info.canvasContext.enqueueFrameWork(std::move(functor));
}
+ virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
+ if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
+
+ if (info) {
+ auto functor = std::bind(
+ std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this,
+ (jlong) info->canvasContext.getFrameNumber());
+
+ info->canvasContext.enqueueFrameWork(std::move(functor));
+ } else {
+ doNotifyPositionLost(0);
+ }
+ }
+
private:
JNIEnv* jnienv() {
JNIEnv* env;
@@ -607,6 +622,21 @@
env->DeleteLocalRef(localref);
}
+ void doNotifyPositionLost(jlong frameNumber) {
+ ATRACE_NAME("SurfaceView position lost");
+
+ JNIEnv* env = jnienv();
+ jobject localref = env->NewLocalRef(mWeakRef);
+ if (CC_UNLIKELY(!localref)) {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ return;
+ }
+
+ env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber);
+ env->DeleteLocalRef(localref);
+ }
+
JavaVM* mVm;
jobject mWeakRef;
};
@@ -701,6 +731,8 @@
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
"updateWindowPositionRT", "(JIIII)V");
+ gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
+ "windowPositionLostRT", "(J)V");
clazz = FindClassOrDie(env, "android/view/RenderNode");
gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
"onRenderNodeDetached", "()V");
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d0c6a8e..13e1d00 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8251,12 +8251,13 @@
<declare-styleable name="Shortcut">
<attr name="shortcutId" format="string" />
<attr name="enabled" />
- <attr name="shortcutIcon" format="reference" />
+ <attr name="icon" />
<attr name="shortcutShortLabel" format="reference" />
<attr name="shortcutLongLabel" format="reference" />
<attr name="shortcutDisabledMessage" format="reference" />
- <attr name="shortcutCategories" format="string" />
- <attr name="shortcutIntentAction" format="string" />
- <attr name="shortcutIntentData" format="string" />
+ </declare-styleable>
+
+ <declare-styleable name="ShortcutCategories">
+ <attr name="name" />
</declare-styleable>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index da31767..c187d2c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2733,13 +2733,9 @@
=============================================================== -->
<eat-comment />
<public type="attr" name="shortcutId" />
- <public type="attr" name="shortcutIcon" />
<public type="attr" name="shortcutShortLabel" />
<public type="attr" name="shortcutLongLabel" />
<public type="attr" name="shortcutDisabledMessage" />
- <public type="attr" name="shortcutCategories" />
- <public type="attr" name="shortcutIntentAction" />
- <public type="attr" name="shortcutIntentData" />
<public type="attr" name="roundIcon" />
<public type="attr" name="contextUri" />
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 5a3300a..f8797bf 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -474,7 +474,7 @@
}
#endif
-void RenderNode::syncDisplayList(TreeObserver* observer) {
+void RenderNode::syncDisplayList(TreeInfo* info) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
@@ -482,7 +482,7 @@
child->renderNode->incParentRefCount();
}
}
- deleteDisplayList(observer);
+ deleteDisplayList(info ? info->observer : nullptr, info);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
@@ -501,15 +501,15 @@
// Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds
damageSelf(info);
- syncDisplayList(info.observer);
+ syncDisplayList(&info);
damageSelf(info);
}
}
-void RenderNode::deleteDisplayList(TreeObserver* observer) {
+void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->decParentRefCount(observer);
+ child->renderNode->decParentRefCount(observer, info);
}
}
delete mDisplayList;
@@ -541,35 +541,38 @@
}
}
-void RenderNode::destroyHardwareResources(TreeObserver* observer) {
+void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
if (mLayer) {
destroyLayer(mLayer);
mLayer = nullptr;
}
if (mDisplayList) {
for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->destroyHardwareResources(observer);
+ child->renderNode->destroyHardwareResources(observer, info);
}
if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can
// drop our current one now
- deleteDisplayList(observer);
+ deleteDisplayList(observer, info);
}
}
}
-void RenderNode::decParentRefCount(TreeObserver* observer) {
+void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) {
LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
mParentCount--;
if (!mParentCount) {
if (observer) {
observer->onMaybeRemovedFromTree(this);
}
+ if (CC_UNLIKELY(mPositionListener.get())) {
+ mPositionListener->onPositionLost(*this, info);
+ }
// If a child of ours is being attached to our parent then this will incorrectly
// destroy its hardware resources. However, this situation is highly unlikely
// and the failure is "just" that the layer is re-created, so this should
// be safe enough
- destroyHardwareResources(observer);
+ destroyHardwareResources(observer, info);
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index acdc3d8..f80be5e 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -196,7 +196,7 @@
}
ANDROID_API virtual void prepareTree(TreeInfo& info);
- void destroyHardwareResources(TreeObserver* observer);
+ void destroyHardwareResources(TreeObserver* observer, TreeInfo* info = nullptr);
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
@@ -228,10 +228,19 @@
OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
#endif
+ // Note: The position callbacks are relying on the listener using
+ // the frameNumber to appropriately batch/synchronize these transactions.
+ // There is no other filtering/batching to ensure that only the "final"
+ // state called once per frame.
class ANDROID_API PositionListener {
public:
virtual ~PositionListener() {}
+ // Called when the RenderNode's position changes
virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
+ // Called when the RenderNode no longer has a position. As in, it's
+ // no longer being drawn.
+ // Note, tree info might be null
+ virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
};
// Note this is not thread safe, this needs to be called
@@ -306,7 +315,7 @@
void syncProperties();
- void syncDisplayList(TreeObserver* observer);
+ void syncDisplayList(TreeInfo* info);
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
@@ -317,11 +326,11 @@
#endif
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
- void deleteDisplayList(TreeObserver* observer);
+ void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
- void decParentRefCount(TreeObserver* observer);
+ void decParentRefCount(TreeObserver* observer, TreeInfo* info = nullptr);
String8 mName;
sp<VirtualLightRefBase> mUserContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 91889d3..542b258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -134,6 +134,7 @@
= SystemProperties.getBoolean("debug.child_notifs", true);
public static final boolean FORCE_REMOTE_INPUT_HISTORY =
SystemProperties.getBoolean("debug.force_remoteinput_history", false);
+ private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -704,10 +705,13 @@
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
mSettingsObserver,
UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false,
- mSettingsObserver,
- UserHandle.USER_ALL);
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
+ false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -2304,16 +2308,20 @@
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
- final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
- 0,
- mCurrentUserId) != 0;
- final boolean remoteInputDpm = (dpmFlags
- & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
-
-
setShowLockscreenNotifications(show && allowedByDpm);
- setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+
+ if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
+ final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+ 0,
+ mCurrentUserId) != 0;
+ final boolean remoteInputDpm =
+ (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
+
+ setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+ } else {
+ setLockScreenAllowRemoteInput(false);
+ }
}
protected abstract void setAreThereNotifications();
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 5527a41..4ed0913 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2323,6 +2323,20 @@
// Deletion helper encountered an error during photo and video deletion.
ACTION_DELETION_HELPER_PHOTOS_VIDEOS_DELETION_FAIL = 473;
+ // OPEN: Settings (root page if there are multiple tabs)
+ // CATEGORY: SETTINGS
+ DASHBOARD_CONTAINER = 474;
+
+ // OPEN: Settings -> SUPPORT TAB
+ // CATEGORY: SETTINGS
+ SUPPORT_FRAGMENT = 475;
+
+ // ACTION: Settings -> Select summary tab.
+ ACTION_SELECT_SUMMARY=476;
+
+ // ACTION: Settings -> Select support tab.
+ ACTION_SELECT_SUPPORT_FRAGMENT = 477;
+
// ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 04a0990..feceb14 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -20,6 +20,7 @@
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -67,6 +68,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -650,7 +652,7 @@
}
private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) {
- if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) {
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
@@ -695,6 +697,10 @@
loadGroupStateLocked(newProfileIds);
}
+ private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
+ return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
@@ -3381,7 +3387,7 @@
if (userInfo != null && userInfo.isManagedProfile()) {
UserInfo parentInfo = mUserManager.getProfileParent(userId);
if (parentInfo != null
- && !mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) {
+ && !isUserRunningAndUnlocked(parentInfo.getUserHandle().getIdentifier())) {
return true;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 334b228..930c151b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2356,7 +2356,8 @@
mConnecting = true;
mConnectedAgent = null;
try {
- if (mActivityManager.bindBackupAgent(app, mode)) {
+ if (mActivityManager.bindBackupAgent(app.packageName, mode,
+ UserHandle.USER_OWNER)) {
Slog.d(TAG, "awaiting agent for " + app);
// success; wait for the agent to arrive
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c044181..bfc9877 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17041,11 +17041,22 @@
// Cause the target app to be launched if necessary and its backup agent
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
- public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
- if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
- "bindBackupAgent: app=" + app + " mode=" + backupMode);
+ public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
+ if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode);
enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
+ IPackageManager pm = AppGlobals.getPackageManager();
+ ApplicationInfo app = null;
+ try {
+ app = pm.getApplicationInfo(packageName, 0, userId);
+ } catch (RemoteException e) {
+ // can't happen; package manager is process-local
+ }
+ if (app == null) {
+ Slog.w(TAG, "Unable to bind backup agent for " + packageName);
+ return false;
+ }
+
synchronized(this) {
// !!! TODO: currently no check here that we're already bound
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ace14ac..d637586 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -682,6 +682,8 @@
changed |= pushOutExcessShortcuts();
}
+ s.verifyStates();
+
if (changed) {
// This will send a notification to the launcher, and also save .
s.packageShortcutsChanged(getPackageName(), getPackageUserId());
@@ -774,6 +776,7 @@
}
removeOrphans();
}
+ adjustRanks();
return changed;
}
@@ -810,7 +813,6 @@
deleteDynamicWithId(shortcut.getId());
}
}
- service.verifyStates();
return changed;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index ec19927..c349b75 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -24,10 +24,10 @@
import android.content.pm.ShortcutInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.net.Uri;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -48,10 +48,12 @@
private static final boolean DEBUG = ShortcutService.DEBUG || false; // DO NOT SUBMIT WITH TRUE
@VisibleForTesting
- static final String METADATA_KEY = "android.pm.Shortcuts";
+ static final String METADATA_KEY = "android.app.shortcuts";
private static final String TAG_SHORTCUTS = "shortcuts";
private static final String TAG_SHORTCUT = "shortcut";
+ private static final String TAG_INTENT = "intent";
+ private static final String TAG_CATEGORIES = "categories";
@Nullable
public static List<ShortcutInfo> parseShortcuts(ShortcutService service,
@@ -60,10 +62,17 @@
List<ShortcutInfo> result = null;
- if (pi != null && pi.activities != null) {
- for (ActivityInfo activityInfo : pi.activities) {
- result = parseShortcutsOneFile(service, activityInfo, packageName, userId, result);
+ try {
+ if (pi != null && pi.activities != null) {
+ for (ActivityInfo activityInfo : pi.activities) {
+ result = parseShortcutsOneFile(service, activityInfo, packageName, userId, result);
+ }
}
+ } catch (RuntimeException e) {
+ // Resource ID mismatch may cause various runtime exceptions when parsing XMLs.
+ service.wtf(
+ "Exception caught while parsing shortcut XML for package=" + packageName, e);
+ return null;
}
return result;
}
@@ -89,14 +98,58 @@
final int maxShortcuts = service.getMaxActivityShortcuts();
int numShortcuts = 0;
+ // We instantiate ShortcutInfo at <shortcut>, but we add it to the list at </shortcut>,
+ // after parsing <intent>. We keep the current one in here.
+ ShortcutInfo currentShortcut = null;
+
+ Set<String> categories = null;
+
outer:
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > 0)) {
+ final int depth = parser.getDepth();
+ final String tag = parser.getName();
+
+ // When a shortcut tag is closing, publish.
+ if ((type == XmlPullParser.END_TAG) && (depth == 2) && (TAG_SHORTCUT.equals(tag))) {
+ if (currentShortcut == null) {
+ // Shortcut was invalid.
+ continue;
+ }
+ final ShortcutInfo si = currentShortcut;
+ currentShortcut = null; // Make sure to null out for the next iteration.
+
+ if (si.getIntent() == null) {
+ Log.e(TAG, "Shortcut " + si.getId() + " has no intent. Skipping it.");
+ continue;
+ }
+
+ if (numShortcuts >= maxShortcuts) {
+ Log.e(TAG, "More than " + maxShortcuts + " shortcuts found for "
+ + activityInfo.getComponentName() + ". Skipping the rest.");
+ return result;
+ }
+ if (categories != null) {
+ si.setCategories(categories);
+ categories = null;
+ }
+
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ result.add(si);
+ numShortcuts++;
+ rank++;
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, "Shortcut added: " + si.toInsecureString());
+ }
+ continue;
+ }
+
+ // Otherwise, just look at start tags.
if (type != XmlPullParser.START_TAG) {
continue;
}
- final int depth = parser.getDepth();
- final String tag = parser.getName();
if (depth == 1 && TAG_SHORTCUTS.equals(tag)) {
continue; // Root tag.
@@ -104,35 +157,73 @@
if (depth == 2 && TAG_SHORTCUT.equals(tag)) {
final ShortcutInfo si = parseShortcutAttributes(
service, attrs, packageName, activity, userId, rank);
+ if (si == null) {
+ // Shortcut was invalid.
+ continue;
+ }
if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Shortcut=" + si);
+ Slog.d(TAG, "Shortcut found: " + si.toInsecureString());
}
if (result != null) {
for (int i = result.size() - 1; i >= 0; i--) {
if (si.getId().equals(result.get(i).getId())) {
- Slog.w(TAG, "Duplicate shortcut ID detected, skipping.");
+ Log.e(TAG, "Duplicate shortcut ID detected. Skipping it.");
continue outer;
}
}
}
+ if (!si.isEnabled()) {
+ // Just set the default intent to disabled shortcuts.
+ si.setIntent(new Intent(Intent.ACTION_VIEW));
+ }
+ currentShortcut = si;
+ categories = null;
+ continue;
+ }
+ if (depth == 3 && TAG_INTENT.equals(tag)) {
+ if ((currentShortcut == null)
+ || (currentShortcut.getIntentNoExtras() != null)
+ || !currentShortcut.isEnabled()) {
+ Log.e(TAG, "Ignoring excessive intent tag.");
+ continue;
+ }
- if (si != null) {
- if (numShortcuts >= maxShortcuts) {
- Slog.w(TAG, "More than " + maxShortcuts + " shortcuts found for "
- + activityInfo.getComponentName() + ", ignoring the rest.");
- return result;
- }
-
- if (result == null) {
- result = new ArrayList<>();
- }
- result.add(si);
- numShortcuts++;
- rank++;
+ final Intent intent = Intent.parseIntent(service.mContext.getResources(),
+ parser, attrs);
+ if (TextUtils.isEmpty(intent.getAction())) {
+ Log.e(TAG, "Shortcut intent action must be provided. activity=" + activity);
+ continue;
+ }
+ try {
+ currentShortcut.setIntent(intent);
+ } catch (RuntimeException e) {
+ // This shouldn't happen because intents in XML can't have complicated
+ // extras, but just in case Intent.parseIntent() supports such a thing one
+ // day.
+ Log.e(TAG, "Shortcut's extras contain un-persistable values. Skipping it.");
+ continue;
}
continue;
}
- Slog.w(TAG, "Unknown tag " + tag);
+ if (depth == 3 && TAG_CATEGORIES.equals(tag)) {
+ if ((currentShortcut == null)
+ || (currentShortcut.getCategories() != null)) {
+ continue;
+ }
+ final String name = parseCategories(service, attrs);
+ if (TextUtils.isEmpty(name)) {
+ Log.e(TAG, "Empty category found. activity=" + activity);
+ continue;
+ }
+
+ if (categories == null) {
+ categories = new ArraySet<>();
+ }
+ categories.add(name);
+ continue;
+ }
+
+ Log.w(TAG, "Unknown tag " + tag + " at depth " + depth);
}
} finally {
if (parser != null) {
@@ -142,6 +233,16 @@
return result;
}
+ private static String parseCategories(ShortcutService service, AttributeSet attrs) {
+ final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs,
+ R.styleable.ShortcutCategories);
+ try {
+ return sa.getString(R.styleable.ShortcutCategories_name);
+ } finally {
+ sa.recycle();
+ }
+ }
+
private static ShortcutInfo parseShortcutAttributes(ShortcutService service,
AttributeSet attrs, String packageName, ComponentName activity,
@UserIdInt int userId, int rank) {
@@ -150,14 +251,11 @@
try {
final String id = sa.getString(R.styleable.Shortcut_shortcutId);
final boolean enabled = sa.getBoolean(R.styleable.Shortcut_enabled, true);
- final int iconResId = sa.getResourceId(R.styleable.Shortcut_shortcutIcon, 0);
+ final int iconResId = sa.getResourceId(R.styleable.Shortcut_icon, 0);
final int titleResId = sa.getResourceId(R.styleable.Shortcut_shortcutShortLabel, 0);
final int textResId = sa.getResourceId(R.styleable.Shortcut_shortcutLongLabel, 0);
final int disabledMessageResId = sa.getResourceId(
R.styleable.Shortcut_shortcutDisabledMessage, 0);
- final String categories = sa.getString(R.styleable.Shortcut_shortcutCategories);
- String intentAction = sa.getString(R.styleable.Shortcut_shortcutIntentAction);
- final String intentData = sa.getString(R.styleable.Shortcut_shortcutIntentData);
if (TextUtils.isEmpty(id)) {
Slog.w(TAG, "Shortcut ID must be provided. activity=" + activity);
@@ -167,31 +265,6 @@
Slog.w(TAG, "Shortcut title must be provided. activity=" + activity);
return null;
}
- if (TextUtils.isEmpty(intentAction)) {
- if (enabled) {
- Slog.w(TAG, "Shortcut intent action must be provided. activity=" + activity);
- return null;
- } else {
- // Disabled shortcut doesn't have to have an action, but just set VIEW as the
- // default.
- intentAction = Intent.ACTION_VIEW;
- }
- }
-
- final ArraySet<String> categoriesSet;
- if (categories == null) {
- categoriesSet = null;
- } else {
- final String[] arr = categories.split(":");
- categoriesSet = new ArraySet<>(arr.length);
- for (String v : arr) {
- categoriesSet.add(v);
- }
- }
- final Intent intent = new Intent(intentAction);
- if (!TextUtils.isEmpty(intentData)) {
- intent.setData(Uri.parse(intentData));
- }
return createShortcutFromManifest(
service,
@@ -202,8 +275,6 @@
titleResId,
textResId,
disabledMessageResId,
- categoriesSet,
- intent,
rank,
iconResId,
enabled);
@@ -214,8 +285,8 @@
private static ShortcutInfo createShortcutFromManifest(ShortcutService service,
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
- int titleResId, int textResId, int disabledMessageResId, Set<String> categories,
- Intent intent, int rank, int iconResId, boolean enabled) {
+ int titleResId, int textResId, int disabledMessageResId,
+ int rank, int iconResId, boolean enabled) {
final int flags =
(enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED)
@@ -239,8 +310,8 @@
null, // disabled message string
disabledMessageResId,
null, // disabled message res name
- categories,
- intent,
+ null, // categories
+ null, // intent
null, // intent extras
rank,
null, // extras
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1619168..be8eeed 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1510,6 +1510,10 @@
ps.clearAllImplicitRanks();
assignImplicitRanks(newShortcuts);
+ for (int i = 0; i < size; i++) {
+ fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
+ }
+
// First, remove all un-pinned; dynamic shortcuts
ps.deleteAllDynamicShortcuts();
diff --git a/services/tests/servicestests/res/drawable/icon3.png b/services/tests/servicestests/res/drawable/icon3.png
new file mode 100644
index 0000000..64eb294
--- /dev/null
+++ b/services/tests/servicestests/res/drawable/icon3.png
Binary files differ
diff --git a/services/tests/servicestests/res/xml/shortcut_1.xml b/services/tests/servicestests/res/xml/shortcut_1.xml
index f6d54fc..e3f9172 100644
--- a/services/tests/servicestests/res/xml/shortcut_1.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1.xml
@@ -2,12 +2,17 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="data1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="data1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_alt.xml b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
index bf14f49..2d5e8e7 100644
--- a/services/tests/servicestests/res/xml/shortcut_1_alt.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
@@ -17,12 +17,17 @@
<shortcut
android:shortcutId="ms1-alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="data1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="data1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_disable.xml b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
index 81a84b4..e3ee3a0 100644
--- a/services/tests/servicestests/res/xml/shortcut_1_disable.xml
+++ b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
@@ -17,7 +17,7 @@
<shortcut
android:shortcutId="ms1"
android:enabled="false"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
diff --git a/services/tests/servicestests/res/xml/shortcut_2.xml b/services/tests/servicestests/res/xml/shortcut_2.xml
index 96ed382..f7ea803 100644
--- a/services/tests/servicestests/res/xml/shortcut_2.xml
+++ b/services/tests/servicestests/res/xml/shortcut_2.xml
@@ -17,23 +17,32 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- android:shortcutIntentData="http://a.b.c/2"
- />
+ >
+ <intent
+ android:action="action2"
+ android:data="http://a.b.c/2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
index 2f814b7..b00ec60 100644
--- a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
+++ b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
@@ -17,11 +17,19 @@
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="action1"
- />
+ >
+ <intent
+ android:action="action1"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title2"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5.xml b/services/tests/servicestests/res/xml/shortcut_5.xml
index 56dba0e..9551100 100644
--- a/services/tests/servicestests/res/xml/shortcut_5.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5.xml
@@ -17,37 +17,69 @@
<shortcut
android:shortcutId="ms1"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms4"
- android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ android:shortcutShortLabel="@string/shortcut_title2"
+ >
+ <intent
+ android:action="android.intent.action.VIEW2"
+ >
+ </intent>
+ <categories />
+ <categories android:name="" />
+ <categories android:name="cat" />
+ </shortcut>
<shortcut
android:shortcutId="ms5"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="action"
+ android:data="http://www/"
+ android:targetPackage="abc"
+ android:targetClass=".xyz"
+ android:mimeType="foo/bar"
+ >
+ <categories android:name="cat1" />
+ <categories android:name="cat2" />
+ <extra android:name="key1" android:value="value1" />
+ <extra android:name="key2" android:value="value2" />
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_alt.xml b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
index 74085d9..f79cd6f 100644
--- a/services/tests/servicestests/res/xml/shortcut_5_alt.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
@@ -17,37 +17,58 @@
<shortcut
android:shortcutId="ms1_alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms2_alt"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms4_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms5_alt"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
index 3d6eb22..d5b7c8f 100644
--- a/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
+++ b/services/tests/servicestests/res/xml/shortcut_5_reverse.xml
@@ -17,37 +17,62 @@
<shortcut
android:shortcutId="ms5"
android:enabled="true"
- android:shortcutIcon="@drawable/icon1"
+ android:icon="@drawable/icon1"
android:shortcutShortLabel="@string/shortcut_title1"
android:shortcutLongLabel="@string/shortcut_text1"
android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
- android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
- android:shortcutIntentAction="action1"
- android:shortcutIntentData="http://a.b.c/1"
- />
+ >
+ <intent
+ android:action="action1"
+ android:data="http://a.b.c/1"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ <categories android:name="android.shortcut.media" />
+ </shortcut>
<shortcut
android:shortcutId="ms4"
android:enabled="true"
- android:shortcutIcon="@drawable/icon2"
+ android:icon="@drawable/icon2"
android:shortcutShortLabel="@string/shortcut_title2"
android:shortcutLongLabel="@string/shortcut_text2"
android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
- android:shortcutCategories="android.shortcut.conversation"
- android:shortcutIntentAction="action2"
- />
+ >
+ <intent
+ android:action="action2"
+ >
+ </intent>
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
<shortcut
android:shortcutId="ms3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms2"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="ms1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="action"
+ >
+ <categories android:name="cat1" />
+ <categories android:name="cat2" />
+ <extra android:name="key1" android:value="value1" />
+ <extra android:name="key2" android:value="value2" />
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_1.xml b/services/tests/servicestests/res/xml/shortcut_error_1.xml
index 5822496..3990d02 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_1.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_1.xml
@@ -16,11 +16,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
<shortcut
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="x1"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_2.xml b/services/tests/servicestests/res/xml/shortcut_error_2.xml
index ca67ec7..a6f7150 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_2.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_2.xml
@@ -16,11 +16,19 @@
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
<shortcut
android:shortcutId="manifest-shortcut-3"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
<shortcut
android:shortcutId="x2"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
index fb7b31c..a7b9b84 100644
--- a/services/tests/servicestests/res/xml/shortcut_error_3.xml
+++ b/services/tests/servicestests/res/xml/shortcut_error_3.xml
@@ -21,6 +21,10 @@
<shortcut
android:shortcutId="x3"
android:shortcutShortLabel="@string/shortcut_title1"
- android:shortcutIntentAction="android.intent.action.VIEW"
- />
+ >
+ <intent
+ android:action="android.intent.action.VIEW"
+ >
+ </intent>
+ </shortcut>
</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_4.xml b/services/tests/servicestests/res/xml/shortcut_error_4.xml
new file mode 100644
index 0000000..3697bb4
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_error_4.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- This is valid -->
+ <shortcut
+ android:shortcutId="ms1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action1" />
+ </shortcut>
+
+ <!-- Invalid: no intent -->
+ <shortcut
+ android:shortcutId="ms_ignored1"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ />
+
+ <!-- Valid: more than one intent; first one will be picked. -->
+ <shortcut
+ android:shortcutId="ms2"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action2_1" />
+ <intent android:action="action2_2" />
+ </shortcut>
+
+ <!-- Valid: disabled shortcut doesn't need an intent -->
+ <shortcut
+ android:shortcutId="ms3"
+ android:enabled="false"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ />
+
+ <!-- Valid, but disabled shortcut's intent will be ignored. -->
+ <shortcut
+ android:shortcutId="ms4"
+ android:enabled="false"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:action="action4" />
+ </shortcut>
+
+ <!-- Invalid, no intent action -->
+ <shortcut
+ android:shortcutId="ms_ignored2"
+ android:shortcutShortLabel="@string/shortcut_title1"
+ >
+ <intent android:data="x"/>
+ </shortcut>
+</shortcuts>
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index de06047..56232c0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4884,6 +4884,117 @@
});
}
+ public void testManifestShortcuts_intentDefinitions() {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_error_4);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // Make sure invalid ones are not published.
+ // Note that at this point disabled ones don't show up because they weren't pinned.
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2")
+ .areAllManifest()
+ .areAllNotDynamic()
+ .areAllNotPinned()
+ .areAllImmutable()
+ .areAllEnabled()
+ .forShortcutWithId("ms1", si -> {
+ assertTrue(si.isEnabled());
+ assertEquals("action1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms2", si -> {
+ assertTrue(si.isEnabled());
+ assertEquals("action2_1", si.getIntent().getAction());
+ });
+ });
+
+ // Publish 5 enabled to pin some, so we can later test disabled manfiest shortcuts..
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_5);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ // Make sure 5 manifest shortcuts are published.
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllManifest()
+ .areAllNotDynamic()
+ .areAllNotPinned()
+ .areAllImmutable()
+ .areAllEnabled();
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("ms3", "ms4", "ms5"), HANDLE_USER_0);
+ });
+
+ // Make sure they're pinned.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .selectByIds("ms1", "ms2")
+ .areAllNotPinned()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms3", "ms4", "ms5")
+ .areAllPinned()
+ .areAllEnabled();
+ });
+
+ // Update the app.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_error_4);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ // Make sure 3, 4 and 5 still exist but disabled.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllNotDynamic()
+ .areAllImmutable()
+
+ .selectByIds("ms1", "ms2")
+ .areAllManifest()
+ .areAllNotPinned()
+ .areAllEnabled()
+
+ .revertToOriginalList()
+ .selectByIds("ms3", "ms4", "ms5")
+ .areAllNotManifest()
+ .areAllPinned()
+ .areAllDisabled()
+
+ .revertToOriginalList()
+ .forShortcutWithId("ms1", si -> {
+ assertEquals(si.getId(), "action1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms2", si -> {
+ assertEquals(si.getId(), "action2_1", si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms3", si -> {
+ assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms4", si -> {
+ assertEquals(si.getId(), Intent.ACTION_VIEW, si.getIntent().getAction());
+ })
+ .forShortcutWithId("ms5", si -> {
+ assertEquals(si.getId(), "action", si.getIntent().getAction());
+ });
+ });
+ }
+
public void testManifestShortcuts_checkAllFields() {
mService.handleUnlockUser(USER_0);
@@ -4897,63 +5008,95 @@
// Only the valid one is published.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
- mManager.getManifestShortcuts()))),
- "ms1", "ms2", "ms3", "ms4", "ms5");
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "ms3", "ms4", "ms5")
+ .areAllManifest()
+ .areAllImmutable()
+ .areAllEnabled()
+ .areAllNotPinned()
+ .areAllNotDynamic()
- // check first shortcut.
- ShortcutInfo si = getCallerShortcut("ms1");
+ .forShortcutWithId("ms1", si -> {
+ assertEquals(R.drawable.icon1, si.getIconResourceId());
+ assertEquals(new ComponentName(CALLING_PACKAGE_1,
+ ShortcutActivity.class.getName()),
+ si.getActivity());
- assertEquals("ms1", si.getId());
- assertEquals(R.drawable.icon1, si.getIconResourceId());
- assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
- si.getActivity());
+ assertEquals(R.string.shortcut_title1, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
+ assertEquals(R.string.shortcut_text1, si.getTextResId());
+ assertEquals("r" + R.string.shortcut_text1, si.getTextResName());
+ assertEquals(R.string.shortcut_disabled_message1,
+ si.getDisabledMessageResourceId());
+ assertEquals("r" + R.string.shortcut_disabled_message1,
+ si.getDisabledMessageResName());
- assertEquals(R.string.shortcut_title1, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
- assertEquals(R.string.shortcut_text1, si.getTextResId());
- assertEquals("r" + R.string.shortcut_text1, si.getTextResName());
- assertEquals(R.string.shortcut_disabled_message1, si.getDisabledMessageResourceId());
- assertEquals("r" + R.string.shortcut_disabled_message1, si.getDisabledMessageResName());
+ assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
+ si.getCategories());
+ assertEquals("action1", si.getIntent().getAction());
+ assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
+ })
- assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
- si.getCategories());
- assertEquals("action1", si.getIntent().getAction());
- assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
+ .forShortcutWithId("ms2", si -> {
+ assertEquals("ms2", si.getId());
+ assertEquals(R.drawable.icon2, si.getIconResourceId());
- // check another
- si = getCallerShortcut("ms2");
+ assertEquals(R.string.shortcut_title2, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
+ assertEquals(R.string.shortcut_text2, si.getTextResId());
+ assertEquals("r" + R.string.shortcut_text2, si.getTextResName());
+ assertEquals(R.string.shortcut_disabled_message2,
+ si.getDisabledMessageResourceId());
+ assertEquals("r" + R.string.shortcut_disabled_message2,
+ si.getDisabledMessageResName());
- assertEquals("ms2", si.getId());
- assertEquals(R.drawable.icon2, si.getIconResourceId());
+ assertEquals(set("android.shortcut.conversation"), si.getCategories());
+ assertEquals("action2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
- assertEquals(R.string.shortcut_title2, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
- assertEquals(R.string.shortcut_text2, si.getTextResId());
- assertEquals("r" + R.string.shortcut_text2, si.getTextResName());
- assertEquals(R.string.shortcut_disabled_message2, si.getDisabledMessageResourceId());
- assertEquals("r" + R.string.shortcut_disabled_message2, si.getDisabledMessageResName());
+ .forShortcutWithId("ms3", si -> {
+ assertEquals(0, si.getIconResourceId());
+ assertEquals(R.string.shortcut_title1, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
- assertEquals(set("android.shortcut.conversation"), si.getCategories());
- assertEquals("action2", si.getIntent().getAction());
- assertEquals(null, si.getIntent().getData());
+ assertEquals(0, si.getTextResId());
+ assertEquals(null, si.getTextResName());
+ assertEquals(0, si.getDisabledMessageResourceId());
+ assertEquals(null, si.getDisabledMessageResName());
- // check another
- si = getCallerShortcut("ms3");
+ assertEmpty(si.getCategories());
+ assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
- assertEquals("ms3", si.getId());
- assertEquals(0, si.getIconResourceId());
- assertEquals(R.string.shortcut_title1, si.getTitleResId());
- assertEquals("r" + R.string.shortcut_title1, si.getTitleResName());
+ .forShortcutWithId("ms4", si -> {
+ assertEquals(0, si.getIconResourceId());
+ assertEquals(R.string.shortcut_title2, si.getTitleResId());
+ assertEquals("r" + R.string.shortcut_title2, si.getTitleResName());
- assertEquals(0, si.getTextResId());
- assertEquals(null, si.getTextResName());
- assertEquals(0, si.getDisabledMessageResourceId());
- assertEquals(null, si.getDisabledMessageResName());
+ assertEquals(0, si.getTextResId());
+ assertEquals(null, si.getTextResName());
+ assertEquals(0, si.getDisabledMessageResourceId());
+ assertEquals(null, si.getDisabledMessageResName());
- assertEquals(null, si.getCategories());
- assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
- assertEquals(null, si.getIntent().getData());
+ assertEquals(set("cat"), si.getCategories());
+ assertEquals("android.intent.action.VIEW2", si.getIntent().getAction());
+ assertEquals(null, si.getIntent().getData());
+ })
+
+ .forShortcutWithId("ms5", si -> {
+ si = getCallerShortcut("ms5");
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals("http://www/", si.getIntent().getData().toString());
+ assertEquals("foo/bar", si.getIntent().getType());
+ assertEquals(
+ new ComponentName("abc", ".xyz"), si.getIntent().getComponent());
+
+ assertEquals(set("cat1", "cat2"), si.getIntent().getCategories());
+ assertEquals("value1", si.getIntent().getStringExtra("key1"));
+ assertEquals("value2", si.getIntent().getStringExtra("key2"));
+ });
});
}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 7ba4c68..712bc1e 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -43,9 +43,11 @@
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.test.MoreAsserts;
+import android.util.ArraySet;
import android.util.Log;
import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -66,6 +68,7 @@
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -259,9 +262,12 @@
}
}
- public static <T> List<T> assertEmpty(List<T> list) {
- assertEquals(0, list.size());
- return list;
+ public static <T extends Collection<?>> T assertEmpty(T collection) {
+ if (collection == null) {
+ return collection; // okay.
+ }
+ assertEquals(0, collection.size());
+ return collection;
}
public static List<ShortcutInfo> filter(List<ShortcutInfo> list, Predicate<ShortcutInfo> p) {
@@ -653,42 +659,73 @@
* New style assertion that allows chained calls.
*/
public static class ShortcutListAsserter {
+ private final ShortcutListAsserter mOriginal;
private final List<ShortcutInfo> mList;
ShortcutListAsserter(List<ShortcutInfo> list) {
+ this(null, list);
+ }
+
+ private ShortcutListAsserter(ShortcutListAsserter original, List<ShortcutInfo> list) {
+ mOriginal = original == null ? this : original;
mList = new ArrayList<>(list);
}
+ public ShortcutListAsserter revertToOriginalList() {
+ return mOriginal;
+ }
+
public ShortcutListAsserter selectDynamic() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
filter(mList, ShortcutInfo::isDynamic));
}
public ShortcutListAsserter selectManifest() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
filter(mList, ShortcutInfo::isManifestShortcut));
}
public ShortcutListAsserter selectPinned() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
filter(mList, ShortcutInfo::isPinned));
}
public ShortcutListAsserter selectByActivity(ComponentName activity) {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.filterByActivity(mList, activity));
}
public ShortcutListAsserter selectByChangedSince(long time) {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.changedSince(mList, time));
}
+ public ShortcutListAsserter selectByIds(String... ids) {
+ final Set<String> idSet = set(ids);
+ final ArrayList<ShortcutInfo> selected = new ArrayList<>();
+ for (ShortcutInfo si : mList) {
+ if (idSet.contains(si.getId())) {
+ selected.add(si);
+ idSet.remove(si.getId());
+ }
+ }
+ if (idSet.size() > 0) {
+ fail("Shortcuts not found for IDs=" + idSet);
+ }
+
+ return new ShortcutListAsserter(this, selected);
+ }
+
public ShortcutListAsserter toSortByRank() {
- return new ShortcutListAsserter(
+ return new ShortcutListAsserter(this,
ShortcutManagerTestUtils.sortedByRank(mList));
}
+ public ShortcutListAsserter call(Consumer<List<ShortcutInfo>> c) {
+ c.accept(mList);
+ return this;
+ }
+
public ShortcutListAsserter haveIds(String... expectedIds) {
assertShortcutIds(mList, expectedIds);
return this;
@@ -701,7 +738,8 @@
private ShortcutListAsserter haveSequentialRanks() {
for (int i = 0; i < mList.size(); i++) {
- assertEquals("Rank not sequential", i, mList.get(i).getRank());
+ final ShortcutInfo si = mList.get(i);
+ assertEquals("Rank not sequential: id=" + si.getId(), i, si.getRank());
}
return this;
}
@@ -717,5 +755,87 @@
assertEquals(0, mList.size());
return this;
}
+
+ public ShortcutListAsserter areAllDynamic() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isDynamic()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotDynamic() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isDynamic()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllPinned() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isPinned()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotPinned() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isPinned()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllManifest() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isManifestShortcut()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllNotManifest() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isManifestShortcut()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllImmutable() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isImmutable()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllMutable() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isImmutable()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllEnabled() {
+ forAllShortcuts(s -> assertTrue("id=" + s.getId(), s.isEnabled()));
+ return this;
+ }
+
+ public ShortcutListAsserter areAllDisabled() {
+ forAllShortcuts(s -> assertFalse("id=" + s.getId(), s.isEnabled()));
+ return this;
+ }
+
+ public ShortcutListAsserter forAllShortcuts(Consumer<ShortcutInfo> sa) {
+ for (int i = 0; i < mList.size(); i++) {
+ final ShortcutInfo si = mList.get(i);
+ sa.accept(si);
+ }
+ return this;
+ }
+
+ public ShortcutListAsserter forShortcut(Predicate<ShortcutInfo> p,
+ Consumer<ShortcutInfo> sa) {
+ boolean found = false;
+ for (int i = 0; i < mList.size(); i++) {
+ final ShortcutInfo si = mList.get(i);
+ if (p.test(si)) {
+ found = true;
+ try {
+ sa.accept(si);
+ } catch (Throwable e) {
+ throw new AssertionError("Assertion failed for shortcut " + si.getId(), e);
+ }
+ }
+ }
+ assertTrue("Shortcut with the given condition not found.", found);
+ return this;
+ }
+
+ public ShortcutListAsserter forShortcutWithId(String id, Consumer<ShortcutInfo> sa) {
+ forShortcut(si -> si.getId().equals(id), sa);
+
+ return this;
+ }
}
}
diff --git a/telephony/java/android/telephony/TelephonyHistogram.java b/telephony/java/android/telephony/TelephonyHistogram.java
index 9d9ce72..e1c3d7b 100644
--- a/telephony/java/android/telephony/TelephonyHistogram.java
+++ b/telephony/java/android/telephony/TelephonyHistogram.java
@@ -31,35 +31,35 @@
public final class TelephonyHistogram implements Parcelable {
// Type of Telephony histogram Eg: RIL histogram will have all timing data associated with
// RIL calls. Similarly we can have any other Telephony histogram.
- private final int category;
+ private final int mCategory;
// Unique Id identifying a sample within particular category of histogram
- private final int id;
+ private final int mId;
// Min time taken in ms
- private int minTimeMs;
+ private int mMinTimeMs;
// Max time taken in ms
- private int maxTimeMs;
+ private int mMaxTimeMs;
// Average time taken in ms
- private int averageTimeMs;
+ private int mAverageTimeMs;
// Total count of samples
- private int sampleCount;
+ private int mSampleCount;
// Array storing time taken for first #RANGE_CALCULATION_COUNT samples of histogram.
- private int[] initialTimings;
+ private int[] mInitialTimings;
// Total number of time ranges expected (must be greater than 1)
- private final int bucketCount;
+ private final int mBucketCount;
// Array storing endpoints of range buckets. Calculated based on values of minTime & maxTime
// after totalTimeCount is #RANGE_CALCULATION_COUNT.
- private final int[] bucketEndPoints;
+ private final int[] mBucketEndPoints;
// Array storing counts for each time range starting from smallest value range
- private final int[] bucketCounters;
+ private final int[] mBucketCounters;
/**
* Constant for Telephony category
@@ -81,69 +81,85 @@
if (bucketCount <= 1) {
throw new IllegalArgumentException("Invalid number of buckets");
}
- this.category = category;
- this.id = id;
- this.minTimeMs = Integer.MAX_VALUE;
- this.maxTimeMs = 0;
- this.averageTimeMs = 0;
- this.sampleCount = 0;
- initialTimings = new int[RANGE_CALCULATION_COUNT];
- this.bucketCount = bucketCount;
- bucketEndPoints = new int[bucketCount - 1];
- bucketCounters = new int[bucketCount];
+ mCategory = category;
+ mId = id;
+ mMinTimeMs = Integer.MAX_VALUE;
+ mMaxTimeMs = 0;
+ mAverageTimeMs = 0;
+ mSampleCount = 0;
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
+ mBucketCount = bucketCount;
+ mBucketEndPoints = new int[bucketCount - 1];
+ mBucketCounters = new int[bucketCount];
}
public TelephonyHistogram(TelephonyHistogram th) {
- category = th.getCategory();
- id = th.getId();
- minTimeMs = th.getMinTime();
- maxTimeMs = th.getMaxTime();
- averageTimeMs = th.getAverageTime();
- sampleCount = th.getSampleCount();
- initialTimings = th.getInitialTimings();
- bucketCount = th.getBucketCount();
- bucketEndPoints = th.getBucketEndPoints();
- bucketCounters = th.getBucketCounters();
+ mCategory = th.getCategory();
+ mId = th.getId();
+ mMinTimeMs = th.getMinTime();
+ mMaxTimeMs = th.getMaxTime();
+ mAverageTimeMs = th.getAverageTime();
+ mSampleCount = th.getSampleCount();
+ mInitialTimings = th.getInitialTimings();
+ mBucketCount = th.getBucketCount();
+ mBucketEndPoints = th.getBucketEndPoints();
+ mBucketCounters = th.getBucketCounters();
}
public int getCategory() {
- return category;
+ return mCategory;
}
public int getId() {
- return id;
+ return mId;
}
public int getMinTime() {
- return minTimeMs;
+ return mMinTimeMs;
}
public int getMaxTime() {
- return maxTimeMs;
+ return mMaxTimeMs;
}
public int getAverageTime() {
- return averageTimeMs;
+ return mAverageTimeMs;
}
public int getSampleCount () {
- return sampleCount;
+ return mSampleCount;
}
private int[] getInitialTimings() {
- return initialTimings;
+ return mInitialTimings;
}
public int getBucketCount() {
- return bucketCount;
+ return mBucketCount;
}
public int[] getBucketEndPoints() {
- return getDeepCopyOfArray(bucketEndPoints);
+ if (mSampleCount > 1 && mSampleCount < 10) {
+ int[] tempEndPoints = new int[mBucketCount - 1];
+ calculateBucketEndPoints(tempEndPoints);
+ return tempEndPoints;
+ } else {
+ return getDeepCopyOfArray(mBucketEndPoints);
+ }
}
public int[] getBucketCounters() {
- return getDeepCopyOfArray(bucketCounters);
+ if (mSampleCount > 1 && mSampleCount < 10) {
+ int[] tempEndPoints = new int[mBucketCount - 1];
+ int[] tempBucketCounters = new int[mBucketCount];
+ calculateBucketEndPoints(tempEndPoints);
+ for (int j = 0; j < mSampleCount; j++) {
+ addToBucketCounter(tempEndPoints, tempBucketCounters, mInitialTimings[j]);
+ }
+ return tempBucketCounters;
+ } else {
+ return getDeepCopyOfArray(mBucketCounters);
+ }
}
private int[] getDeepCopyOfArray(int[] array) {
@@ -152,7 +168,7 @@
return clone;
}
- private void addToBucketCounter(int time) {
+ private void addToBucketCounter(int[] bucketEndPoints, int[] bucketCounters, int time) {
int i;
for (i = 0; i < bucketEndPoints.length; i++) {
if (time <= bucketEndPoints[i]) {
@@ -163,6 +179,13 @@
bucketCounters[i]++;
}
+ private void calculateBucketEndPoints(int[] bucketEndPoints) {
+ for (int i = 1; i < mBucketCount; i++) {
+ int endPt = mMinTimeMs + (i * (mMaxTimeMs - mMinTimeMs)) / mBucketCount;
+ bucketEndPoints[i - 1] = endPt;
+ }
+ }
+
// Add new value of time taken
// This function updates minTime, maxTime, averageTime & totalTimeCount every time it is
// called. initialTimings[] is updated if totalTimeCount <= #RANGE_CALCULATION_COUNT. When
@@ -172,65 +195,62 @@
public void addTimeTaken(int time) {
// Initialize all fields if its first entry or if integer overflow is going to occur while
// trying to calculate averageTime
- if (sampleCount == 0 || (sampleCount == Integer.MAX_VALUE)) {
- if (sampleCount == 0) {
- minTimeMs = time;
- maxTimeMs = time;
- averageTimeMs = time;
+ if (mSampleCount == 0 || (mSampleCount == Integer.MAX_VALUE)) {
+ if (mSampleCount == 0) {
+ mMinTimeMs = time;
+ mMaxTimeMs = time;
+ mAverageTimeMs = time;
} else {
- initialTimings = new int[RANGE_CALCULATION_COUNT];
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
}
- sampleCount = 1;
- Arrays.fill(initialTimings, 0);
- initialTimings[0] = time;
- Arrays.fill(bucketEndPoints, 0);
- Arrays.fill(bucketCounters, 0);
+ mSampleCount = 1;
+ Arrays.fill(mInitialTimings, 0);
+ mInitialTimings[0] = time;
+ Arrays.fill(mBucketEndPoints, 0);
+ Arrays.fill(mBucketCounters, 0);
} else {
- if (time < minTimeMs) {
- minTimeMs = time;
+ if (time < mMinTimeMs) {
+ mMinTimeMs = time;
}
- if (time > maxTimeMs) {
- maxTimeMs = time;
+ if (time > mMaxTimeMs) {
+ mMaxTimeMs = time;
}
- long totalTime = ((long)averageTimeMs) * sampleCount + time;
- averageTimeMs = (int)(totalTime/++sampleCount);
+ long totalTime = ((long)mAverageTimeMs) * mSampleCount + time;
+ mAverageTimeMs = (int)(totalTime/++mSampleCount);
- if (sampleCount < RANGE_CALCULATION_COUNT) {
- initialTimings[sampleCount - 1] = time;
- } else if (sampleCount == RANGE_CALCULATION_COUNT) {
- initialTimings[sampleCount - 1] = time;
+ if (mSampleCount < RANGE_CALCULATION_COUNT) {
+ mInitialTimings[mSampleCount - 1] = time;
+ } else if (mSampleCount == RANGE_CALCULATION_COUNT) {
+ mInitialTimings[mSampleCount - 1] = time;
// Calculate bucket endpoints based on bucketCount expected
- for (int i = 1; i < bucketCount; i++) {
- int endPt = minTimeMs + (i * (maxTimeMs - minTimeMs)) / bucketCount;
- bucketEndPoints[i - 1] = endPt;
- }
+ calculateBucketEndPoints(mBucketEndPoints);
// Use values stored in initialTimings[] to update bucketCounters
for (int j = 0; j < RANGE_CALCULATION_COUNT; j++) {
- addToBucketCounter(initialTimings[j]);
+ addToBucketCounter(mBucketEndPoints, mBucketCounters, mInitialTimings[j]);
}
- initialTimings = null;
+ mInitialTimings = null;
} else {
- addToBucketCounter(time);
+ addToBucketCounter(mBucketEndPoints, mBucketCounters, time);
}
}
}
public String toString() {
- String basic = " Histogram id = " + id + " Time(ms): min = " + minTimeMs + " max = "
- + maxTimeMs + " avg = " + averageTimeMs + " Count = " + sampleCount;
- if (sampleCount < RANGE_CALCULATION_COUNT) {
+ String basic = " Histogram id = " + mId + " Time(ms): min = " + mMinTimeMs + " max = "
+ + mMaxTimeMs + " avg = " + mAverageTimeMs + " Count = " + mSampleCount;
+ if (mSampleCount < RANGE_CALCULATION_COUNT) {
return basic;
} else {
StringBuffer intervals = new StringBuffer(" Interval Endpoints:");
- for (int i = 0; i < bucketEndPoints.length; i++) {
- intervals.append(" " + bucketEndPoints[i]);
+ for (int i = 0; i < mBucketEndPoints.length; i++) {
+ intervals.append(" " + mBucketEndPoints[i]);
}
intervals.append(" Interval counters:");
- for (int i = 0; i < bucketCounters.length; i++) {
- intervals.append(" " + bucketCounters[i]);
+ for (int i = 0; i < mBucketCounters.length; i++) {
+ intervals.append(" " + mBucketCounters[i]);
}
return basic + intervals;
}
@@ -251,39 +271,39 @@
};
public TelephonyHistogram(Parcel in) {
- category = in.readInt();
- id = in.readInt();
- minTimeMs = in.readInt();
- maxTimeMs = in.readInt();
- averageTimeMs = in.readInt();
- sampleCount = in.readInt();
+ mCategory = in.readInt();
+ mId = in.readInt();
+ mMinTimeMs = in.readInt();
+ mMaxTimeMs = in.readInt();
+ mAverageTimeMs = in.readInt();
+ mSampleCount = in.readInt();
if (in.readInt() == PRESENT) {
- initialTimings = new int[RANGE_CALCULATION_COUNT];
- in.readIntArray(initialTimings);
+ mInitialTimings = new int[RANGE_CALCULATION_COUNT];
+ in.readIntArray(mInitialTimings);
}
- bucketCount = in.readInt();
- bucketEndPoints = new int[bucketCount - 1];
- in.readIntArray(bucketEndPoints);
- bucketCounters = new int[bucketCount];
- in.readIntArray(bucketCounters);
+ mBucketCount = in.readInt();
+ mBucketEndPoints = new int[mBucketCount - 1];
+ in.readIntArray(mBucketEndPoints);
+ mBucketCounters = new int[mBucketCount];
+ in.readIntArray(mBucketCounters);
}
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(category);
- out.writeInt(id);
- out.writeInt(minTimeMs);
- out.writeInt(maxTimeMs);
- out.writeInt(averageTimeMs);
- out.writeInt(sampleCount);
- if (initialTimings == null) {
+ out.writeInt(mCategory);
+ out.writeInt(mId);
+ out.writeInt(mMinTimeMs);
+ out.writeInt(mMaxTimeMs);
+ out.writeInt(mAverageTimeMs);
+ out.writeInt(mSampleCount);
+ if (mInitialTimings == null) {
out.writeInt(ABSENT);
} else {
out.writeInt(PRESENT);
- out.writeIntArray(initialTimings);
+ out.writeIntArray(mInitialTimings);
}
- out.writeInt(bucketCount);
- out.writeIntArray(bucketEndPoints);
- out.writeIntArray(bucketCounters);
+ out.writeInt(mBucketCount);
+ out.writeIntArray(mBucketEndPoints);
+ out.writeIntArray(mBucketCounters);
}
@Override