Merge "Add logs, reorder bugreport."
diff --git a/api/current.txt b/api/current.txt
index 9df1764..a4c933f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24096,6 +24096,7 @@
field public static final java.lang.String COLUMN_AUTHOR = "author";
field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
@@ -24238,11 +24239,13 @@
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
+ field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index eed1718..a806153 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25885,6 +25885,7 @@
field public static final java.lang.String COLUMN_AUTHOR = "author";
field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
@@ -26108,11 +26109,13 @@
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
+ field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index 114060d..b47331b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -24189,6 +24189,7 @@
field public static final java.lang.String COLUMN_AUTHOR = "author";
field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
@@ -24331,11 +24332,13 @@
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
+ field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 7015381..51b2d3d 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -553,8 +553,12 @@
sessionParams.abiOverride = checkAbiArgument(nextOptionData());
break;
case "--ephemeral":
+ case "--instant":
sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
break;
+ case "--full":
+ sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
+ break;
case "--user":
params.userId = UserHandle.parseUserArg(nextOptionData());
break;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 333e412..1652299 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1687,7 +1687,7 @@
public int installExistingPackageAsUser(String packageName, int userId)
throws NameNotFoundException {
try {
- int res = mPM.installExistingPackageAsUser(packageName, userId,
+ int res = mPM.installExistingPackageAsUser(packageName, userId, 0 /*installFlags*/,
PackageManager.INSTALL_REASON_UNKNOWN);
if (res == INSTALL_FAILED_INVALID_URI) {
throw new NameNotFoundException("Package " + packageName + " doesn't exist");
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 45a46b3..812daf8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3684,7 +3684,8 @@
mContext, backgroundColor);
mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(
mContext, backgroundColor);
- mActionBarColor = NotificationColorUtil.resolveActionBarColor(backgroundColor);
+ mActionBarColor = NotificationColorUtil.resolveActionBarColor(mContext,
+ backgroundColor);
}
}
@@ -4166,12 +4167,21 @@
mN.extras.putCharSequence(EXTRA_SUB_TEXT, newSummary);
}
}
+ Boolean colorized = (Boolean) mN.extras.get(EXTRA_COLORIZED);
+ mN.extras.putBoolean(EXTRA_COLORIZED, false);
+
RemoteViews header = makeNotificationHeader();
+
if (summary != null) {
mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);
} else {
mN.extras.remove(EXTRA_SUB_TEXT);
}
+ if (colorized != null) {
+ mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
+ } else {
+ mN.extras.remove(EXTRA_COLORIZED);
+ }
mN.color = color;
return header;
}
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index e6cae69..56609eb 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -284,8 +284,6 @@
/** Whether or not the intent filter is visible to ephemeral apps. */
private boolean mVisibleToEphemeral;
- /** Whether or not the intent filter is part of an ephemeral app. */
- private boolean mEphemeral;
// These functions are the start of more optimized code for managing
// the string sets... not yet implemented.
@@ -656,19 +654,10 @@
mVisibleToEphemeral = visibleToEmphemeral;
}
/** @hide */
- public boolean isVisibleToEphemeral() {
+ public boolean isVisibleToInstantApp() {
return mVisibleToEphemeral;
}
- /** @hide */
- public void setEphemeral(boolean ephemeral) {
- mEphemeral = ephemeral;
- }
- /** @hide */
- public boolean isEphemeral() {
- return mEphemeral;
- }
-
/**
* Add a new Intent action to match against. If any actions are included
* in the filter, then an Intent's action must be one of those values for
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1fa4181..9737b11 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -498,11 +498,12 @@
public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;
/**
- * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
- * and for most purposes is considered as not installed.
- * {@hide}
+ * Value for {@link #privateFlags}: {@code true} if the application is installed
+ * as instant app.
+ *
+ * @hide
*/
- public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 7;
+ public static final int PRIVATE_FLAG_INSTANT = 1 << 7;
/**
* When set, at least one component inside this application is direct boot
@@ -681,7 +682,21 @@
*
* {@hide}
*/
- public String seinfo = "default";
+ public String seInfo = "default";
+
+ /**
+ * The seinfo tag generated per-user. This value may change based upon the
+ * user's configuration. For example, when an instant app is installed for
+ * a user. It is an error if this field is ever {@code null} when trying to
+ * start a new process.
+ * <p>NOTE: We need to separate this out because we modify per-user values
+ * multiple times. This needs to be refactored since we're performing more
+ * work than necessary and these values should only be set once. When that
+ * happens, we can merge the per-user value with the seInfo state above.
+ *
+ * {@hide}
+ */
+ public String seInfoUser;
/**
* Paths to all shared libraries this application is linked against. This
@@ -1009,8 +1024,9 @@
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + Arrays.toString(resourceDirs));
}
- if ((flags&DUMP_FLAG_DETAILS) != 0 && seinfo != null) {
- pw.println(prefix + "seinfo=" + seinfo);
+ if ((flags&DUMP_FLAG_DETAILS) != 0 && seInfo != null) {
+ pw.println(prefix + "seinfo=" + seInfo);
+ pw.println(prefix + "seinfoUser=" + seInfoUser);
}
pw.println(prefix + "dataDir=" + dataDir);
if ((flags&DUMP_FLAG_DETAILS) != 0) {
@@ -1120,7 +1136,8 @@
primaryCpuAbi = orig.primaryCpuAbi;
secondaryCpuAbi = orig.secondaryCpuAbi;
resourceDirs = orig.resourceDirs;
- seinfo = orig.seinfo;
+ seInfo = orig.seInfo;
+ seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
deviceEncryptedDataDir = deviceProtectedDataDir = orig.deviceProtectedDataDir;
@@ -1181,7 +1198,8 @@
dest.writeString(primaryCpuAbi);
dest.writeString(secondaryCpuAbi);
dest.writeStringArray(resourceDirs);
- dest.writeString(seinfo);
+ dest.writeString(seInfo);
+ dest.writeString(seInfoUser);
dest.writeStringArray(sharedLibraryFiles);
dest.writeString(dataDir);
dest.writeString(deviceProtectedDataDir);
@@ -1242,7 +1260,8 @@
primaryCpuAbi = source.readString();
secondaryCpuAbi = source.readString();
resourceDirs = source.readStringArray();
- seinfo = source.readString();
+ seInfo = source.readString();
+ seInfoUser = source.readString();
sharedLibraryFiles = source.readStringArray();
dataDir = source.readString();
deviceEncryptedDataDir = deviceProtectedDataDir = source.readString();
@@ -1330,7 +1349,6 @@
} else {
dataDir = credentialProtectedDataDir;
}
- // TODO: modify per-user ephemerality
}
/**
@@ -1415,7 +1433,7 @@
* @hide
*/
public boolean isInstantApp() {
- return (privateFlags & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0;
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
}
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9d36a73..ffb777d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -553,7 +553,8 @@
boolean setInstallLocation(int loc);
int getInstallLocation();
- int installExistingPackageAsUser(String packageName, int userId, int installReason);
+ int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+ int installReason);
void verifyPendingInstall(int id, int verificationCode);
void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 4de967c..278a6d0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1096,9 +1096,11 @@
@SystemApi
public void setInstallAsInstantApp(boolean isInstantApp) {
if (isInstantApp) {
- installFlags |= PackageManager.INSTALL_EPHEMERAL;
+ installFlags |= PackageManager.INSTALL_INSTANT_APP;
+ installFlags &= ~PackageManager.INSTALL_FULL_APP;
} else {
- installFlags &= ~PackageManager.INSTALL_EPHEMERAL;
+ installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
+ installFlags |= PackageManager.INSTALL_FULL_APP;
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 308153d..5733982 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -452,17 +452,17 @@
/**
* Internal {@link PackageInfo} flag: include components that are part of an
- * ephemeral app. By default, ephemeral components are not matched.
+ * instant app. By default, instant app components are not matched.
* @hide
*/
- public static final int MATCH_EPHEMERAL = 0x00800000;
+ public static final int MATCH_INSTANT = 0x00800000;
/**
* Internal {@link PackageInfo} flag: include only components that are exposed to
* ephemeral apps.
* @hide
*/
- public static final int MATCH_VISIBLE_TO_EPHEMERAL_ONLY = 0x01000000;
+ public static final int MATCH_VISIBLE_TO_INSTANT_APP_ONLY = 0x01000000;
/**
* Internal flag used to indicate that a system component has done their
@@ -613,7 +613,7 @@
INSTALL_GRANT_RUNTIME_PERMISSIONS,
INSTALL_FORCE_VOLUME_UUID,
INSTALL_FORCE_PERMISSION_PROMPT,
- INSTALL_EPHEMERAL,
+ INSTALL_INSTANT_APP,
INSTALL_DONT_KILL_APP,
})
@Retention(RetentionPolicy.SOURCE)
@@ -714,7 +714,16 @@
*
* @hide
*/
- public static final int INSTALL_EPHEMERAL = 0x00000800;
+ public static final int INSTALL_INSTANT_APP = 0x00000800;
+
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that this package is
+ * to be installed as a heavy weight app. This is fundamentally the opposite of
+ * {@link #INSTALL_INSTANT_APP}.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FULL_APP = 0x00004000;
/**
* Flag parameter for {@link #installPackage} to indicate that this package contains
@@ -1185,12 +1194,12 @@
public static final int INSTALL_FAILED_ABORTED = -115;
/**
- * Installation failed return code: ephemeral app installs are incompatible with some
+ * Installation failed return code: instant app installs are incompatible with some
* other installation flags supplied for the operation; or other circumstances such
- * as trying to upgrade a system app via an ephemeral install.
+ * as trying to upgrade a system app via an instant app install.
* @hide
*/
- public static final int INSTALL_FAILED_EPHEMERAL_INVALID = -116;
+ public static final int INSTALL_FAILED_INSTANT_APP_INVALID = -116;
/** @hide */
@IntDef(flag = true, value = {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7a9aaaf..98e71a0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -720,6 +720,8 @@
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
public final static int PARSE_ENFORCE_CODE = 1<<10;
+ /** @deprecated remove when fixing b/34761192 */
+ @Deprecated
public final static int PARSE_IS_EPHEMERAL = 1<<11;
public final static int PARSE_FORCE_SDK = 1<<12;
@@ -2012,10 +2014,6 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
- if ((flags & PARSE_IS_EPHEMERAL) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
- }
-
if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
}
@@ -4149,11 +4147,8 @@
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
}
- final boolean hasVisibleToEphemeral =
- sa.hasValue(R.styleable.AndroidManifestActivity_visibleToInstantApps);
- final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
- final boolean visibleToEphemeral = isEphemeral
- || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
+ final boolean visibleToEphemeral =
+ sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
if (visibleToEphemeral) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
@@ -4188,8 +4183,6 @@
intent, outError)) {
return null;
}
- intent.setEphemeral(isEphemeral);
- intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in intent filter at "
+ mArchiveSourcePath + " "
@@ -4198,7 +4191,8 @@
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
- if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+ intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
+ if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
} else if (!receiver && parser.getName().equals("preferred")) {
@@ -4207,8 +4201,6 @@
intent, outError)) {
return null;
}
- intent.setEphemeral(isEphemeral);
- intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
if (intent.countActions() == 0) {
Slog.w(TAG, "No actions in preferred at "
+ mArchiveSourcePath + " "
@@ -4220,7 +4212,8 @@
owner.preferredActivityFilters.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
- if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+ intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
+ if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
} else if (parser.getName().equals("meta-data")) {
@@ -4472,9 +4465,8 @@
}
// TODO add visibleToInstantApps attribute to activity alias
- final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
- final boolean visibleToEphemeral = isEphemeral
- || ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
+ final boolean visibleToEphemeral =
+ ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
sa.recycle();
@@ -4502,13 +4494,12 @@
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
- intent.setEphemeral(isEphemeral);
- intent.setVisibleToEphemeral(visibleToEphemeral
- || isWebBrowsableIntent(intent));
+ intent.setVisibleToEphemeral(
+ visibleToEphemeral || isWebBrowsableIntent(intent));
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
- if (intent.isVisibleToEphemeral()) {
+ if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
} else if (parser.getName().equals("meta-data")) {
@@ -4649,11 +4640,8 @@
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
}
- final boolean hasVisibleToEphemeral =
- sa.hasValue(R.styleable.AndroidManifestProvider_visibleToInstantApps);
- final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
- final boolean visibleToEphemeral = isEphemeral
- || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+ final boolean visibleToEphemeral =
+ sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
if (visibleToEphemeral) {
p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
@@ -4681,7 +4669,7 @@
p.info.authority = cpname.intern();
if (!parseProviderTags(
- res, parser, isEphemeral, hasVisibleToEphemeral, visibleToEphemeral, p, outError)) {
+ res, parser, visibleToEphemeral, p, outError)) {
return null;
}
@@ -4689,8 +4677,7 @@
}
private boolean parseProviderTags(Resources res, XmlResourceParser parser,
- boolean isEphemeral, boolean hasVisibleToEphemeral, boolean visibleToEphemeral,
- Provider outInfo, String[] outError)
+ boolean visibleToEphemeral, Provider outInfo, String[] outError)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
@@ -4707,11 +4694,10 @@
intent, outError)) {
return false;
}
- intent.setEphemeral(isEphemeral);
- intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
outInfo.intents.add(intent);
// adjust provider flags when we implicitly expose it via a browsable filter
- if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+ intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
+ if (intent.isVisibleToInstantApp()) {
outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
@@ -4963,11 +4949,8 @@
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
}
- final boolean hasVisibleToEphemeral =
- sa.hasValue(R.styleable.AndroidManifestService_visibleToInstantApps);
- final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
- final boolean visibleToEphemeral = isEphemeral
- || sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
+ final boolean visibleToEphemeral =
+ sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
@@ -4999,10 +4982,9 @@
intent, outError)) {
return null;
}
- intent.setEphemeral(isEphemeral);
- intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
// adjust activity flags when we implicitly expose it via a browsable filter
- if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
+ intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
+ if (intent.isVisibleToInstantApp()) {
s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
s.intents.add(intent);
@@ -6482,6 +6464,9 @@
if (state.stopped) {
return true;
}
+ if (state.instantApp != p.applicationInfo.isInstantApp()) {
+ return true;
+ }
if ((flags & PackageManager.GET_META_DATA) != 0
&& (metaData != null || p.mAppMetaData != null)) {
return true;
@@ -6517,6 +6502,11 @@
} else {
ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
}
+ if (state.instantApp) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
+ } else {
+ ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
+ }
if (state.hidden) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
@@ -6537,6 +6527,7 @@
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
+ ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index e19aa99..24f1164 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -43,6 +43,7 @@
public boolean hidden; // Is the app restricted by owner / admin
public boolean suspended;
public boolean blockUninstall;
+ public boolean instantApp;
public int enabled;
public String lastDisableAppCaller;
public int domainVerificationStatus;
@@ -71,6 +72,7 @@
hidden = o.hidden;
suspended = o.suspended;
blockUninstall = o.blockUninstall;
+ instantApp = o.instantApp;
enabled = o.enabled;
lastDisableAppCaller = o.lastDisableAppCaller;
domainVerificationStatus = o.domainVerificationStatus;
@@ -188,6 +190,9 @@
if (blockUninstall != oldState.blockUninstall) {
return false;
}
+ if (instantApp != oldState.instantApp) {
+ return false;
+ }
if (enabled != oldState.enabled) {
return false;
}
diff --git a/core/java/android/content/pm/SELinuxUtil.java b/core/java/android/content/pm/SELinuxUtil.java
new file mode 100644
index 0000000..871f672
--- /dev/null
+++ b/core/java/android/content/pm/SELinuxUtil.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Utility methods that need to be used in application space.
+ * @hide
+ */
+public final class SELinuxUtil {
+
+ /** Append to existing seinfo label for instant apps @hide */
+ private static final String INSTANT_APP_STR = ":ephemeralapp";
+
+ /** Append to existing seinfo when modifications are complete @hide */
+ private static final String COMPLETE_TAG = "complete";
+ private static final String COMPLETE_STR = ":" + COMPLETE_TAG;
+
+ /** @hide */
+ public static String assignSeinfoUser(PackageUserState userState) {
+ String seInfo = "";
+ if (userState.instantApp)
+ seInfo += INSTANT_APP_STR;
+ seInfo += COMPLETE_STR;
+ return seInfo;
+ }
+
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 7cdb3ce..39f4d42 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -311,11 +311,6 @@
}
/** {@hide} */
- public static File getDataAppEphemeralDirectory(String volumeUuid) {
- return new File(getDataDirectory(volumeUuid), "app-ephemeral");
- }
-
- /** {@hide} */
public static File getDataUserCeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user");
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2dfba28..b554e2d 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4128,20 +4128,20 @@
}
/**
- * System settings which can be accessed by ephemeral apps.
+ * System settings which can be accessed by instant apps.
* @hide
*/
- public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+ public static final Set<String> INSTANT_APP_SETTINGS = new ArraySet<>();
static {
- EPHEMERAL_SETTINGS.add(TEXT_AUTO_REPLACE);
- EPHEMERAL_SETTINGS.add(TEXT_AUTO_CAPS);
- EPHEMERAL_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
- EPHEMERAL_SETTINGS.add(TEXT_SHOW_PASSWORD);
- EPHEMERAL_SETTINGS.add(DATE_FORMAT);
- EPHEMERAL_SETTINGS.add(FONT_SCALE);
- EPHEMERAL_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
- EPHEMERAL_SETTINGS.add(TIME_12_24);
- EPHEMERAL_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+ INSTANT_APP_SETTINGS.add(TEXT_AUTO_REPLACE);
+ INSTANT_APP_SETTINGS.add(TEXT_AUTO_CAPS);
+ INSTANT_APP_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+ INSTANT_APP_SETTINGS.add(TEXT_SHOW_PASSWORD);
+ INSTANT_APP_SETTINGS.add(DATE_FORMAT);
+ INSTANT_APP_SETTINGS.add(FONT_SCALE);
+ INSTANT_APP_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+ INSTANT_APP_SETTINGS.add(TIME_12_24);
+ INSTANT_APP_SETTINGS.add(SOUND_EFFECTS_ENABLED);
}
/**
@@ -6988,17 +6988,17 @@
}
/**
- * Secure settings which can be accessed by ephemeral apps.
+ * Secure settings which can be accessed by instant apps.
* @hide
*/
- public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+ public static final Set<String> INSTANT_APP_SETTINGS = new ArraySet<>();
static {
- EPHEMERAL_SETTINGS.add(ENABLED_ACCESSIBILITY_SERVICES);
- EPHEMERAL_SETTINGS.add(ACCESSIBILITY_SPEAK_PASSWORD);
- EPHEMERAL_SETTINGS.add(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ INSTANT_APP_SETTINGS.add(ENABLED_ACCESSIBILITY_SERVICES);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_SPEAK_PASSWORD);
+ INSTANT_APP_SETTINGS.add(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
- EPHEMERAL_SETTINGS.add(DEFAULT_INPUT_METHOD);
- EPHEMERAL_SETTINGS.add(ENABLED_INPUT_METHODS);
+ INSTANT_APP_SETTINGS.add(DEFAULT_INPUT_METHOD);
+ INSTANT_APP_SETTINGS.add(ENABLED_INPUT_METHODS);
}
/**
@@ -10136,16 +10136,16 @@
public static final String CELL_ON = "cell_on";
/**
- * Global settings which can be accessed by ephemeral apps.
+ * Global settings which can be accessed by instant apps.
* @hide
*/
- public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+ public static final Set<String> INSTANT_APP_SETTINGS = new ArraySet<>();
static {
- EPHEMERAL_SETTINGS.add(WAIT_FOR_DEBUGGER);
- EPHEMERAL_SETTINGS.add(DEVICE_PROVISIONED);
- EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
- EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
- EPHEMERAL_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
+ INSTANT_APP_SETTINGS.add(WAIT_FOR_DEBUGGER);
+ INSTANT_APP_SETTINGS.add(DEVICE_PROVISIONED);
+ INSTANT_APP_SETTINGS.add(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
+ INSTANT_APP_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
+ INSTANT_APP_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
}
/**
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index eec3cb0..e088717 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -534,7 +534,7 @@
final int prefer;
final boolean checkBoth;
boolean ephemeral = false;
- if ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
prefer = RECOMMEND_INSTALL_INTERNAL;
ephemeral = true;
checkBoth = false;
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index b4890b7..44b21b4 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -456,7 +456,10 @@
}
}
- public static int resolveActionBarColor(int backgroundColor) {
+ public static int resolveActionBarColor(Context context, int backgroundColor) {
+ if (backgroundColor == Notification.COLOR_DEFAULT) {
+ return context.getColor(com.android.internal.R.color.notification_action_list);
+ }
boolean useDark = shouldUseDark(backgroundColor);
final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
ColorUtilsFromCompat.colorToLAB(backgroundColor, result);
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 00e8c05..ff90160 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -98,6 +98,8 @@
mUpdateTexImage = false;
doUpdateTexImage();
}
+ GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
+ static_cast<GlLayer*>(mLayer)->setRenderTarget(renderTarget);
}
if (mTransform) {
mLayer->getTransform().load(*mTransform);
@@ -140,12 +142,8 @@
}
#endif
mSurfaceTexture->getTransformMatrix(transform);
- GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
- LOG_ALWAYS_FATAL_IF(renderTarget != GL_TEXTURE_2D && renderTarget != GL_TEXTURE_EXTERNAL_OES,
- "doUpdateTexImage target %x, 2d %x, EXT %x",
- renderTarget, GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES);
- updateLayer(forceFilter, renderTarget, transform);
+ updateLayer(forceFilter, transform);
}
}
@@ -155,28 +153,17 @@
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
- updateLayer(false, GL_NONE, identityMatrix.data);
+ updateLayer(false, identityMatrix.data);
VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
vkLayer->updateTexture();
}
-void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
- const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
-
- if (mLayer->getApi() == Layer::Api::OpenGL) {
- GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
- if (renderTarget != glLayer->getRenderTarget()) {
- glLayer->setRenderTarget(renderTarget);
- glLayer->bindTexture();
- glLayer->setFilter(GL_NEAREST, false, true);
- glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
- }
- }
}
void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 6717361..6164e47 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -101,7 +101,7 @@
void detachSurfaceTexture();
- void updateLayer(bool forceFilter, GLenum renderTarget, const float* textureTransform);
+ void updateLayer(bool forceFilter, const float* textureTransform);
void destroyLayer();
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index aacad54..070e954 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -55,9 +55,15 @@
texture.deleteTexture();
}
-void GlLayer::bindTexture() const {
- if (texture.mId) {
- caches.textureState().bindTexture(texture.target(), texture.mId);
+void GlLayer::setRenderTarget(GLenum renderTarget) {
+ if (renderTarget != getRenderTarget()) {
+ // new render target: bind with new target, and update filter/wrap
+ texture.mTarget = renderTarget;
+ if (texture.mId) {
+ caches.textureState().bindTexture(texture.target(), texture.mId);
+ }
+ texture.setFilter(GL_NEAREST, false, true);
+ texture.setWrap(GL_CLAMP_TO_EDGE, false, true);
}
}
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 85ddaff..20aaf4a 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -68,23 +68,12 @@
return texture.target();
}
- inline void setRenderTarget(GLenum renderTarget) {
- texture.mTarget = renderTarget;
- }
-
inline bool isRenderable() const {
return texture.target() != GL_NONE;
}
- void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
- texture.setWrap(wrap, bindTexture, force);
- }
+ void setRenderTarget(GLenum renderTarget);
- void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
- texture.setFilter(filter, bindTexture, force);
- }
-
- void bindTexture() const;
void generateTexture();
/**
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index de80ee3..f2b0eb3 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -128,6 +128,8 @@
return false;
}
+ // acquire most recent buffer for drawing
+ deferredLayer->updateTexImage();
deferredLayer->apply();
SkCanvas canvas(*bitmap);
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 8a5d9cc..acd6110 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -120,6 +120,8 @@
bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
ATRACE_CALL();
+ // acquire most recent buffer for drawing
+ layer->updateTexImage();
layer->apply();
return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 3e52c39..64ec58d 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -74,7 +74,11 @@
layerUpdater->setTransform(&transform);
// updateLayer so it's ready to draw
- layerUpdater->updateLayer(true, GL_TEXTURE_EXTERNAL_OES, Matrix4::identity().data);
+ layerUpdater->updateLayer(true, Matrix4::identity().data);
+ if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
+ static_cast<GlLayer*>(layerUpdater->backingLayer())->setRenderTarget(
+ GL_TEXTURE_EXTERNAL_OES);
+ }
return layerUpdater;
}
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index 1ef9dba..87d897e 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,12 @@
// push the deferred updates to the layer
Matrix4 scaledMatrix;
scaledMatrix.loadScale(0.5, 0.5, 0.0);
- layerUpdater->updateLayer(true, GL_TEXTURE_EXTERNAL_OES, scaledMatrix.data);
+ layerUpdater->updateLayer(true, scaledMatrix.data);
+ if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
+ GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
+ glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
+ }
+
// the backing layer should now have all the properties applied.
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index ddbd542e..45f88f3 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1977,6 +1977,24 @@
public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
/**
+ * The flag indicating whether this TV program is browsable or not.
+ *
+ * <p>This column can only be set by system apps. For other applications, it is a read-only
+ * column. Trying to modify it may cause {@link SecurityException}.
+ *
+ * <p>A value of 1 indicates that the program is browsable and can be shown to users in
+ * the UI. A value of 0 indicates that the program should be hidden from users and the
+ * application who changes this value to 0 should send
+ * {@link TvInputManager#ACTION_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
+ * to notify this change.
+ *
+ * <p>This value is set to 1 (browsable) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_BROWSABLE = "browsable";
+
+ /**
* The internal ID used by individual TV input services.
*
* <p>This is internal to the provider that inserted it, and should not be decoded by other
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index b630270..4c2b031 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -325,23 +325,39 @@
"android.media.tv.action.VIEW_RECORDING_SCHEDULES";
/**
+ * Action sent by the system to tell the target TV input that one of its program's browsable
+ * state is disabled, i.e., it will no longer be shown to users, which, for example, might
+ * be a result of users' interaction with UI.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_PROGRAM_ID} the program ID as a long integer.
+ * </ul>
+ */
+ public static final String ACTION_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
+
+ /**
* Action sent by an application telling the system to set the given channel as browsable.
*
* <p>The intent must contain the following bundle parameters:
* <ul>
- * <li>{@link #EXTRA_CHANNEL_ID} then channel ID as an integer.
+ * <li>{@link #EXTRA_CHANNEL_ID} the channel ID as a long integer.
* <li>{@link #EXTRA_PACKAGE_NAME} the package name of the requesting application.
* </ul>
*/
public static final String ACTION_MAKE_CHANNEL_BROWSABLE
= "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
- /** The key for a bundle parameter containing a channel ID as an integer */
+ /** The key for a bundle parameter containing a channel ID as a long integer */
public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
/** The key for a bundle parameter containing a package name as a string. */
public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ /** The key for a bundle parameter containing a program ID as a long integer */
+ public static final String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
+
private final ITvInputManager mService;
private final Object mLock = new Object();
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 11e2a71..8653523 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -215,6 +215,13 @@
return colorAccent;
}
+ public static Drawable getDrawable(Context context, int attr) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+ Drawable drawable = ta.getDrawable(0);
+ ta.recycle();
+ return drawable;
+ }
+
/**
* Determine whether a package is a "system package", in which case certain things (like
* disabling notifications or disabling the package altogether) should be disallowed.
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index 4c11197..0fc9a4d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -116,7 +116,7 @@
if (info == null || !info.enabled
|| (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier(),
- PackageManager.INSTALL_REASON_UNKNOWN);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN);
if (DEBUG) {
Log.d(TAG, "Installing " + packageName);
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 4df199c..8cfec7a 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -146,7 +146,7 @@
mHelper.applyUserAppsStates(mockListener);
verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN);
verify(mIpm, times(1)).setApplicationHiddenSettingAsUser("app2", false, testUserId);
verify(mockListener).onDisableUiForPackage("app2");
verify(mPm, times(1)).deletePackageAsUser(eq("app3"), any(IPackageDeleteObserver.class),
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index edcb9b5..a3a8553 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1531,14 +1531,14 @@
}
}
- private Set<String> getEphemeralAccessibleSettings(int settingsType) {
+ private Set<String> getInstantAppAccessibleSettings(int settingsType) {
switch (settingsType) {
case SETTINGS_TYPE_GLOBAL:
- return Settings.Global.EPHEMERAL_SETTINGS;
+ return Settings.Global.INSTANT_APP_SETTINGS;
case SETTINGS_TYPE_SECURE:
- return Settings.Secure.EPHEMERAL_SETTINGS;
+ return Settings.Secure.INSTANT_APP_SETTINGS;
case SETTINGS_TYPE_SYSTEM:
- return Settings.System.EPHEMERAL_SETTINGS;
+ return Settings.System.INSTANT_APP_SETTINGS;
default:
throw new IllegalArgumentException("Invalid settings type: " + settingsType);
}
@@ -1547,7 +1547,7 @@
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
if (ai.isInstantApp()) {
- return new ArrayList<String>(getEphemeralAccessibleSettings(settingsType));
+ return new ArrayList<String>(getInstantAppAccessibleSettings(settingsType));
} else {
return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
}
@@ -1561,7 +1561,7 @@
if (!ai.isInstantApp()) {
return;
}
- if (!getEphemeralAccessibleSettings(settingsType).contains(settingName)) {
+ if (!getInstantAppAccessibleSettings(settingsType).contains(settingName)) {
throw new SecurityException("Setting " + settingName + " is not accessible from"
+ " ephemeral package " + getCallingPackage());
}
diff --git a/packages/SystemUI/res/drawable/ic_remove_circle.xml b/packages/SystemUI/res/drawable/ic_remove_circle.xml
new file mode 100644
index 0000000..439cc78
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_remove_circle.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:tint="#db4437"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
+ <path android:fillColor="@android:color/white"
+ android:pathData="M24,4C12.95,4,4,12.95,4,24
+ s8.95,20,20,20,20-8.95,20-20
+ S35.05,4,24,4zm10,22H14v-4h20v4z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/preference_widget_radiobutton.xml b/packages/SystemUI/res/layout/preference_widget_radiobutton.xml
new file mode 100644
index 0000000..b3ec43d
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_radiobutton.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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.
+-->
+
+<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
+ inside android.R.layout.preference. -->
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:focusable="false"
+ android:clickable="false" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 67def4f..77de9a2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1527,14 +1527,12 @@
<!-- SysUI Tuner: Button that controls layout of navigation bar [CHAR LIMIT=60] -->
<string name="nav_bar_layout">Layout</string>
- <!-- SysUI Tuner: Label for section of settings about the left nav button [CHAR LIMIT=60] -->
- <string name="nav_bar_left">Left</string>
-
- <!-- SysUI Tuner: Label for section of settings about the right nav button [CHAR LIMIT=60] -->
- <string name="nav_bar_right">Right</string>
+ <!-- SysUI Tuner: Setting for button type in nav bar [CHAR LIMIT=60] -->
+ <string name="left_nav_bar_button_type">Extra left button type</string>
<!-- SysUI Tuner: Setting for button type in nav bar [CHAR LIMIT=60] -->
- <string name="nav_bar_button_type">Button type</string>
+ <string name="right_nav_bar_button_type">Extra right button type</string>
+
<!-- SysUI Tuner: Added to nav bar option to indicate it is the default [CHAR LIMIT=60] -->
<string name="nav_bar_default"> (default)</string>
@@ -1543,7 +1541,7 @@
<string-array name="nav_bar_buttons">
<item>Clipboard</item>
<item>Keycode</item>
- <item>Menu / Keyboard Switcher</item>
+ <item>Keyboard switcher</item>
<item>None</item>
</string-array>
<string-array name="nav_bar_button_values" translatable="false">
@@ -1555,10 +1553,10 @@
<!-- SysUI Tuner: Labels for different types of navigation bar layouts [CHAR LIMIT=60] -->
<string-array name="nav_bar_layouts">
- <item>Divided (default)</item>
- <item>Centered</item>
- <item>Left-aligned</item>
- <item>Right-aligned</item>
+ <item>Normal</item>
+ <item>Compact</item>
+ <item>Left-leaning</item>
+ <item>Right-leaning</item>
</string-array>
<string-array name="nav_bar_layouts_values" translatable="false">
@@ -1569,7 +1567,7 @@
</string-array>
<!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
- <string name="menu_ime">Menu / Keyboard Switcher</string>
+ <string name="menu_ime">Keyboard switcher</string>
<!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
<string name="save">Save</string>
<!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
@@ -1585,10 +1583,16 @@
<string name="accessibility_key">Custom navigation button</string>
<!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
- <string name="keycode">Keycode</string>
+ <string name="left_keycode">Left keycode</string>
+
+ <!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
+ <string name="right_keycode">Right keycode</string>
<!-- SysUI Tuner: Settings to change nav bar icon [CHAR LIMIT=30] -->
- <string name="icon">Icon</string>
+ <string name="left_icon">Left icon</string>
+
+ <!-- SysUI Tuner: Settings to change nav bar icon [CHAR LIMIT=30] -->
+ <string name="right_icon">Right icon</string>
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
@@ -1725,6 +1729,9 @@
not appear on production builds ever. -->
<string name="tuner_doze_always_on" translatable="false">Always on</string>
+ <!-- SysUI Tuner: Section to customize lockscreen shortcuts [CHAR LIMIT=60] -->
+ <string name="tuner_lock_screen">Lock screen</string>
+
<!-- Making the PIP fullscreen [CHAR LIMIT=25] -->
<string name="pip_phone_expand">Expand</string>
@@ -1760,20 +1767,47 @@
<!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
<string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
- <!-- SysUI Tuner: Group of settings for left lock screen affordance [CHAR LIMIT=60] -->
- <string name="lockscreen_left">Left</string>
-
- <!-- SysUI Tuner: Group of settings for right lock screen affordance [CHAR LIMIT=60] -->
- <string name="lockscreen_right">Right</string>
-
- <!-- SysUI Tuner: Switch controlling whether to customize lock screen button [CHAR LIMIT=60] -->
- <string name="lockscreen_customize">Customize shortcut</string>
+ <!-- SysUI Tuner: Button to select lock screen shortcut [CHAR LIMIT=60] -->
+ <string name="lockscreen_shortcut_left">Left shortcut</string>
<!-- SysUI Tuner: Button to select lock screen shortcut [CHAR LIMIT=60] -->
- <string name="lockscreen_shortcut">Shortcut</string>
+ <string name="lockscreen_shortcut_right">Right shortcut</string>
- <!-- SysUI Tuner: Switch to control if device gets unlocked [CHAR LIMIT=60] -->
- <string name="lockscreen_unlock">Prompt for password</string>
+ <!-- SysUI Tuner: Switch to control if device gets unlocked by left shortcut [CHAR LIMIT=60] -->
+ <string name="lockscreen_unlock_left">Left shortcut also unlocks</string>
+
+ <!-- SysUI Tuner: Switch to control if device gets unlocked by right shortcut [CHAR LIMIT=60] -->
+ <string name="lockscreen_unlock_right">Right shortcut also unlocks</string>
+
+ <!-- SysUI Tuner: Summary of no shortcut being selected [CHAR LIMIT=60] -->
+ <string name="lockscreen_none">None</string>
+
+ <!-- SysUI Tuner: Format string for describing launching an app [CHAR LIMIT=60] -->
+ <string name="tuner_launch_app">Launch <xliff:g id="app" example="Settings">%1$s</xliff:g></string>
+
+ <!-- SysUI Tuner: Label for section of other apps that can be launched [CHAR LIMIT=60] -->
+ <string name="tuner_other_apps">Other apps</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a circle [CHAR LIMIT=60] -->
+ <string name="tuner_circle">Circle</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a plus [CHAR LIMIT=60] -->
+ <string name="tuner_plus">Plus</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a minus [CHAR LIMIT=60] -->
+ <string name="tuner_minus">Minus</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a left [CHAR LIMIT=60] -->
+ <string name="tuner_left">Left</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a right [CHAR LIMIT=60] -->
+ <string name="tuner_right">Right</string>
+
+ <!-- SysUI Tuner: Label for icon shaped like a menu [CHAR LIMIT=60] -->
+ <string name="tuner_menu">Menu</string>
+
+ <!-- SysUI Tuner: App subheading for shortcut selection [CHAR LIMIT=60] -->
+ <string name="tuner_app"><xliff:g id="app">%1$s</xliff:g> app</string>
<!-- Title for the notification channel containing important alerts like low battery. [CHAR LIMIT=NONE] -->
<string name="notification_channel_alerts">Alerts</string>
diff --git a/packages/SystemUI/res/xml/lockscreen_settings.xml b/packages/SystemUI/res/xml/lockscreen_settings.xml
index 73e29af..1e7d266 100644
--- a/packages/SystemUI/res/xml/lockscreen_settings.xml
+++ b/packages/SystemUI/res/xml/lockscreen_settings.xml
@@ -18,42 +18,25 @@
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:title="@string/other">
- <PreferenceCategory
- android:key="left"
- android:title="@string/lockscreen_left">
- <SwitchPreference
- android:key="customize"
- android:title="@string/lockscreen_customize" />
+ <Preference
+ android:key="sysui_keyguard_left"
+ android:title="@string/lockscreen_shortcut_left"
+ android:fragment="com.android.systemui.tuner.ShortcutPicker" />
- <Preference
- android:key="shortcut"
- android:title="@string/lockscreen_shortcut" />
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_keyguard_left_unlock"
+ android:title="@string/lockscreen_unlock_left"
+ sysui:defValue="true" />
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_keyguard_left_unlock"
- android:title="@string/lockscreen_unlock"
- sysui:defValue="true" />
+ <Preference
+ android:key="sysui_keyguard_right"
+ android:title="@string/lockscreen_shortcut_right"
+ android:fragment="com.android.systemui.tuner.ShortcutPicker" />
- </PreferenceCategory>
-
- <PreferenceCategory
- android:key="right"
- android:title="@string/lockscreen_right">
-
- <SwitchPreference
- android:key="customize"
- android:title="@string/lockscreen_customize" />
-
- <Preference
- android:key="shortcut"
- android:title="@string/lockscreen_shortcut" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_keyguard_right_unlock"
- android:title="@string/lockscreen_unlock"
- sysui:defValue="true" />
-
- </PreferenceCategory>
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_keyguard_right_unlock"
+ android:title="@string/lockscreen_unlock_right"
+ sysui:defValue="true" />
</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/nav_bar_tuner.xml b/packages/SystemUI/res/xml/nav_bar_tuner.xml
index 6fa8bec..68e8fad 100644
--- a/packages/SystemUI/res/xml/nav_bar_tuner.xml
+++ b/packages/SystemUI/res/xml/nav_bar_tuner.xml
@@ -18,7 +18,7 @@
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:title="@string/nav_bar">
- <ListPreference
+ <com.android.systemui.tuner.RadioListPreference
android:key="layout"
android:title="@string/nav_bar_layout"
android:summary="%s"
@@ -26,54 +26,42 @@
android:entries="@array/nav_bar_layouts"
android:entryValues="@array/nav_bar_layouts_values" />
- <PreferenceCategory
- android:key="left"
- android:title="@string/nav_bar_left">
+ <com.android.systemui.tuner.RadioListPreference
+ android:key="type_left"
+ android:title="@string/left_nav_bar_button_type"
+ android:persistent="false"
+ android:summary="%s"
+ android:entries="@array/nav_bar_buttons"
+ android:entryValues="@array/nav_bar_button_values" />
- <DropDownPreference
- android:key="type_left"
- android:title="@string/nav_bar_button_type"
- android:persistent="false"
- android:summary="%s"
- android:entries="@array/nav_bar_buttons"
- android:entryValues="@array/nav_bar_button_values" />
+ <Preference
+ android:key="keycode_left"
+ android:persistent="false"
+ android:title="@string/left_keycode" />
- <Preference
- android:key="keycode_left"
- android:persistent="false"
- android:title="@string/keycode" />
+ <com.android.systemui.tuner.RadioListPreference
+ android:key="icon_left"
+ android:persistent="false"
+ android:summary="%s"
+ android:title="@string/left_icon" />
- <com.android.systemui.tuner.BetterListPreference
- android:key="icon_left"
- android:persistent="false"
- android:summary="%s"
- android:title="@string/icon" />
+ <com.android.systemui.tuner.RadioListPreference
+ android:key="type_right"
+ android:title="@string/right_nav_bar_button_type"
+ android:summary="%s"
+ android:persistent="false"
+ android:entries="@array/nav_bar_buttons"
+ android:entryValues="@array/nav_bar_button_values" />
- </PreferenceCategory>
+ <Preference
+ android:key="keycode_right"
+ android:persistent="false"
+ android:title="@string/right_keycode" />
- <PreferenceCategory
- android:key="right"
- android:title="@string/nav_bar_right">
-
- <DropDownPreference
- android:key="type_right"
- android:title="@string/nav_bar_button_type"
- android:summary="%s"
- android:persistent="false"
- android:entries="@array/nav_bar_buttons"
- android:entryValues="@array/nav_bar_button_values" />
-
- <Preference
- android:key="keycode_right"
- android:persistent="false"
- android:title="@string/keycode" />
-
- <com.android.systemui.tuner.BetterListPreference
- android:key="icon_right"
- android:persistent="false"
- android:summary="%s"
- android:title="@string/icon" />
-
- </PreferenceCategory>
+ <com.android.systemui.tuner.RadioListPreference
+ android:key="icon_right"
+ android:persistent="false"
+ android:summary="%s"
+ android:title="@string/right_icon" />
</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 6198ab7..c354811 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -121,6 +121,7 @@
</PreferenceScreen>
+ <!--
<PreferenceScreen
android:key="picture_in_picture"
android:title="@string/picture_in_picture">
@@ -143,6 +144,7 @@
sysui:defValue="false" />
</PreferenceScreen>
+ -->
<Preference
android:key="nav_bar"
@@ -151,15 +153,10 @@
<Preference
android:key="lockscreen"
- android:title="@string/accessibility_desc_lock_screen"
+ android:title="@string/tuner_lock_screen"
android:fragment="com.android.systemui.tuner.LockscreenFragment" />
<Preference
- android:key="other"
- android:title="@string/other"
- android:fragment="com.android.systemui.tuner.OtherPrefs" />
-
- <Preference
android:key="plugins"
android:title="@string/plugins"
android:fragment="com.android.systemui.tuner.PluginFragment" />
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 273b5e3..f1e7d53 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -25,6 +25,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
@@ -74,6 +76,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.function.Consumer;
/**
* Class to handle ugly dependencies throughout sysui until we determine the
@@ -227,6 +230,9 @@
mProviders.put(StatusBarIconController.class, () ->
new StatusBarIconControllerImpl(mContext));
+ mProviders.put(FragmentService.class, () ->
+ new FragmentService(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
@@ -282,17 +288,42 @@
T createDependency();
}
+ private <T> void destroyDependency(Class<T> cls, Consumer<T> destroy) {
+ T dep = (T) mDependencies.remove(cls);
+ if (dep != null && destroy != null) {
+ destroy.accept(dep);
+ }
+ }
+
/**
* Used in separate processes (like tuner settings) to init the dependencies.
*/
public static void initDependencies(Context context) {
if (sDependency != null) return;
Dependency d = new Dependency();
- d.mContext = context.getApplicationContext();
+ d.mContext = context;
d.mComponents = new HashMap<>();
d.start();
}
+ /**
+ * Used in separate process teardown to ensure the context isn't leaked.
+ *
+ * TODO: Remove once PreferenceFragment doesn't reference getActivity()
+ * anymore and these context hacks are no longer needed.
+ */
+ public static void clearDependencies() {
+ sDependency = null;
+ }
+
+ /**
+ * Checks to see if a dependency is instantiated, if it is it removes it from
+ * the cache and calls the destroy callback.
+ */
+ public static <T> void destroy(Class<T> cls, Consumer<T> destroy) {
+ sDependency.destroyDependency(cls, destroy);
+ }
+
public static <T> T get(Class<T> cls) {
return sDependency.getDependency(cls);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 187b557..6caee5f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -67,7 +67,6 @@
*/
private final Class<?>[] SERVICES = new Class[] {
Dependency.class,
- FragmentService.class,
NotificationChannels.class,
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class,
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 0c6bf52..57c75bf 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -32,6 +32,7 @@
import android.view.View;
import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.systemui.Dependency;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginManager;
@@ -171,6 +172,10 @@
return mPlugins;
}
+ void destroy() {
+ mFragments.dispatchDestroy();
+ }
+
public interface FragmentListener {
void onFragmentViewCreated(String tag, Fragment fragment);
@@ -182,8 +187,7 @@
public static FragmentHostManager get(View view) {
try {
- return ((SystemUIApplication) view.getContext().getApplicationContext())
- .getComponent(FragmentService.class).getFragmentHostManager(view);
+ return Dependency.get(FragmentService.class).getFragmentHostManager(view);
} catch (ClassCastException e) {
// TODO: Some auto handling here?
throw e;
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index 85cde10..9a8512d 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -14,6 +14,7 @@
package com.android.systemui.fragments;
+import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
@@ -21,6 +22,7 @@
import android.util.Log;
import android.view.View;
+import com.android.systemui.ConfigurationChangedReceiver;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
@@ -28,16 +30,16 @@
* Holds a map of root views to FragmentHostStates and generates them as needed.
* Also dispatches the configuration changes to all current FragmentHostStates.
*/
-public class FragmentService extends SystemUI {
+public class FragmentService implements ConfigurationChangedReceiver {
private static final String TAG = "FragmentService";
private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
private final Handler mHandler = new Handler();
+ private final Context mContext;
- @Override
- public void start() {
- putComponent(FragmentService.class, this);
+ public FragmentService(Context context) {
+ mContext = context;
}
public FragmentHostManager getFragmentHostManager(View view) {
@@ -50,8 +52,14 @@
return state.getFragmentHostManager();
}
+ public void destroyAll() {
+ for (FragmentHostState state : mHosts.values()) {
+ state.mFragmentHostManager.destroy();
+ }
+ }
+
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
+ public void onConfigurationChanged(Configuration newConfig) {
for (FragmentHostState state : mHosts.values()) {
state.sendConfigurationChange(newConfig);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index f2c3e61..4e30797 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -301,6 +301,7 @@
if (position == mEditIndex) position--;
move(mAccessibilityFromIndex, position, v);
+
notifyDataSetChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index ce72942..ec4ca7a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -102,12 +102,7 @@
mTokenMap.remove(service.getToken());
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
- mMainHandler.post(new Runnable() {
- @Override
- public void run() {
- mHost.getIconController().removeIcon(slot);
- }
- });
+ mMainHandler.post(() -> mHost.getIconController().removeIcon(slot));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3bbaf99..3648a06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -22,7 +22,6 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -331,10 +330,11 @@
boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L));
boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon,
NotificationColorUtil.getInstance(mContext));
+ int color = StatusBarIconView.NO_COLOR;
if (colorize) {
- int color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
- expandedIcon.setImageTintList(ColorStateList.valueOf(color));
+ color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
}
+ expandedIcon.setStaticDrawableColor(color);
}
private void updateLimits() {
@@ -1990,7 +1990,7 @@
mAboveShelf = aboveShelf;
}
- public class NotificationViewState extends ExpandableViewState {
+ public static class NotificationViewState extends ExpandableViewState {
private final StackScrollState mOverallState;
@@ -2011,8 +2011,11 @@
@Override
protected void onYTranslationAnimationFinished(View view) {
super.onYTranslationAnimationFinished(view);
- if (mHeadsupDisappearRunning) {
- setHeadsUpAnimatingAway(false);
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUpAnimatingAway()) {
+ row.setHeadsUpAnimatingAway(false);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 2425076..d4ed1dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -23,6 +23,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.widget.CachingIconView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
@@ -414,7 +415,8 @@
transitionAmount);
float shelfIconSize = icon.getHeight() * icon.getIconScale();
float alpha = 1.0f;
- if (!row.isShowingIcon()) {
+ boolean noIcon = !row.isShowingIcon();
+ if (noIcon) {
// The view currently doesn't have an icon, lets transform it in!
alpha = transitionAmount;
notificationIconSize = shelfIconSize / 2.0f;
@@ -438,6 +440,13 @@
if (row.isAboveShelf()) {
iconState.hidden = true;
}
+ int shelfColor = icon.getStaticDrawableColor();
+ if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) {
+ int notificationColor = row.getNotificationHeader().getOriginalNotificationColor();
+ shelfColor = NotificationUtils.interpolateColors(notificationColor, shelfColor,
+ iconState.iconAppearAmount);
+ }
+ iconState.iconColor = shelfColor;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6283148..cfbb0a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -19,9 +19,11 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -37,7 +39,6 @@
import android.util.Log;
import android.util.Property;
import android.util.TypedValue;
-import android.view.View;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Interpolator;
@@ -50,6 +51,9 @@
import java.text.NumberFormat;
public class StatusBarIconView extends AnimatedImageView {
+ public static final int NO_COLOR = 0;
+ private final int ANIMATION_DURATION_FAST = 100;
+
public static final int STATE_ICON = 0;
public static final int STATE_DOT = 1;
public static final int STATE_HIDDEN = 2;
@@ -104,6 +108,17 @@
private ObjectAnimator mDotAnimator;
private float mDotAppearAmount;
private OnVisibilityChangedListener mOnVisibilityChangedListener;
+ private int mDrawableColor;
+ private int mIconColor;
+ private ValueAnimator mColorAnimator;
+ private int mCurrentSetColor = NO_COLOR;
+ private int mAnimationStartColor = NO_COLOR;
+ private final ValueAnimator.AnimatorUpdateListener mColorUpdater
+ = animation -> {
+ int newColor = NotificationUtils.interpolateColors(mAnimationStartColor, mIconColor,
+ animation.getAnimatedFraction());
+ setColorInternal(newColor);
+ };
public StatusBarIconView(Context context, String slot, Notification notification) {
this(context, slot, notification, false);
@@ -123,7 +138,7 @@
setScaleType(ScaleType.CENTER);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
if (mNotification != null) {
- setIconTint(getContext().getColor(
+ setDecorColor(getContext().getColor(
com.android.internal.R.color.notification_icon_default_color));
}
reloadDimens();
@@ -446,10 +461,66 @@
return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
}
- public void setIconTint(int iconTint) {
+ /**
+ * Set the color that is used to draw decoration like the overflow dot. This will not be applied
+ * to the drawable.
+ */
+ public void setDecorColor(int iconTint) {
mDotPaint.setColor(iconTint);
}
+ /**
+ * Set the static color that should be used for the drawable of this icon if it's not
+ * transitioning this also immediately sets the color.
+ */
+ public void setStaticDrawableColor(int color) {
+ mDrawableColor = color;
+ setColorInternal(color);
+ mIconColor = color;
+ }
+
+ private void setColorInternal(int color) {
+ if (color != NO_COLOR) {
+ setImageTintList(ColorStateList.valueOf(color));
+ } else {
+ setImageTintList(null);
+ }
+ mCurrentSetColor = color;
+ }
+
+ public void setIconColor(int iconColor, boolean animate) {
+ if (mIconColor != iconColor) {
+ mIconColor = iconColor;
+ if (mColorAnimator != null) {
+ mColorAnimator.cancel();
+ }
+ if (mCurrentSetColor == iconColor) {
+ return;
+ }
+ if (animate && mCurrentSetColor != NO_COLOR) {
+ mAnimationStartColor = mCurrentSetColor;
+ mColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mColorAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mColorAnimator.setDuration(ANIMATION_DURATION_FAST);
+ mColorAnimator.addUpdateListener(mColorUpdater);
+ mColorAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mColorAnimator = null;
+ mAnimationStartColor = NO_COLOR;
+ }
+ });
+ mColorAnimator.start();
+ } else {
+ setColorInternal(iconColor);
+ }
+ }
+ }
+
+ public int getStaticDrawableColor() {
+ return mDrawableColor;
+ }
+
public void setVisibleState(int state) {
setVisibleState(state, true /* animate */, null /* endRunnable */);
}
@@ -482,7 +553,7 @@
mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
currentAmount, targetAmount);
mIconAppearAnimator.setInterpolator(interpolator);
- mIconAppearAnimator.setDuration(100);
+ mIconAppearAnimator.setDuration(ANIMATION_DURATION_FAST);
mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -508,7 +579,7 @@
mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
currentAmount, targetAmount);
mDotAnimator.setInterpolator(interpolator);
- mDotAnimator.setDuration(100);
+ mDotAnimator.setDuration(ANIMATION_DURATION_FAST);
final boolean runRunnable = !runnableAdded;
mDotAnimator.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 6d7ab47..707997d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -1,7 +1,6 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
@@ -226,12 +225,13 @@
for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
+ int color = StatusBarIconView.NO_COLOR;
boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
if (colorize) {
- v.setImageTintList(ColorStateList.valueOf(
- DarkIconDispatcher.getTint(mTintArea, v, mIconTint)));
+ color = DarkIconDispatcher.getTint(mTintArea, v, mIconTint);
}
- v.setIconTint(mIconTint);
+ v.setStaticDrawableColor(color);
+ v.setDecorColor(mIconTint);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 571ae26..dc5f98c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -446,6 +446,7 @@
public boolean useFullTransitionAmount;
public boolean useLinearTransitionAmount;
public boolean translateContent;
+ public int iconColor = StatusBarIconView.NO_COLOR;
@Override
public void applyToView(View view) {
@@ -505,6 +506,7 @@
}
}
icon.setVisibleState(visibleState, animationsAllowed);
+ icon.setIconColor(iconColor, needsCannedAnimation && animationsAllowed);
if (animate) {
animateTo(icon, animationProperties);
} else {
@@ -515,6 +517,14 @@
needsCannedAnimation = false;
}
+ @Override
+ public void initFrom(View view) {
+ super.initFrom(view);
+ if (view instanceof StatusBarIconView) {
+ iconColor = ((StatusBarIconView) view).getStaticDrawableColor();
+ }
+ }
+
protected void onYTranslationAnimationFinished(View view) {
if (hidden) {
view.setVisibility(INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/CustomListPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/CustomListPreference.java
new file mode 100644
index 0000000..e50fd5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/CustomListPreference.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.support.v14.preference.ListPreferenceDialogFragment;
+import android.support.v7.preference.ListPreference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class CustomListPreference extends ListPreference {
+
+ public CustomListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
+ OnClickListener listener) {
+ }
+
+ protected void onDialogClosed(boolean positiveResult) {
+ }
+
+ protected Dialog onDialogCreated(DialogFragment fragment, Dialog dialog) {
+ return dialog;
+ }
+
+ protected boolean isAutoClosePreference() {
+ return true;
+ }
+
+ /**
+ * Called when a user is about to choose the given value, to determine if we
+ * should show a confirmation dialog.
+ *
+ * @param value the value the user is about to choose
+ * @return the message to show in a confirmation dialog, or {@code null} to
+ * not request confirmation
+ */
+ protected CharSequence getConfirmationMessage(String value) {
+ return null;
+ }
+
+ protected void onDialogStateRestored(DialogFragment fragment, Dialog dialog,
+ Bundle savedInstanceState) {
+ }
+
+ public static class CustomListPreferenceDialogFragment extends ListPreferenceDialogFragment {
+
+ private static final String KEY_CLICKED_ENTRY_INDEX
+ = "settings.CustomListPrefDialog.KEY_CLICKED_ENTRY_INDEX";
+
+ private int mClickedDialogEntryIndex;
+
+ public static ListPreferenceDialogFragment newInstance(String key) {
+ final ListPreferenceDialogFragment fragment = new CustomListPreferenceDialogFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ public CustomListPreference getCustomizablePreference() {
+ return (CustomListPreference) getPreference();
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ mClickedDialogEntryIndex = getCustomizablePreference()
+ .findIndexOfValue(getCustomizablePreference().getValue());
+ getCustomizablePreference().onPrepareDialogBuilder(builder, getOnItemClickListener());
+ if (!getCustomizablePreference().isAutoClosePreference()) {
+ builder.setPositiveButton(com.android.internal.R.string.ok, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ onItemConfirmed();
+ }
+ });
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Dialog dialog = super.onCreateDialog(savedInstanceState);
+ if (savedInstanceState != null) {
+ mClickedDialogEntryIndex = savedInstanceState.getInt(KEY_CLICKED_ENTRY_INDEX,
+ mClickedDialogEntryIndex);
+ }
+ return getCustomizablePreference().onDialogCreated(this, dialog);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(KEY_CLICKED_ENTRY_INDEX, mClickedDialogEntryIndex);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getCustomizablePreference().onDialogStateRestored(this, getDialog(), savedInstanceState);
+ }
+
+ protected OnClickListener getOnItemClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ setClickedDialogEntryIndex(which);
+ if (getCustomizablePreference().isAutoClosePreference()) {
+ onItemConfirmed();
+ }
+ }
+ };
+ }
+
+ protected void setClickedDialogEntryIndex(int which) {
+ mClickedDialogEntryIndex = which;
+ }
+
+ private String getValue() {
+ final ListPreference preference = getCustomizablePreference();
+ if (mClickedDialogEntryIndex >= 0 && preference.getEntryValues() != null) {
+ return preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+ } else {
+ return null;
+ }
+ }
+
+ protected void onItemConfirmed() {
+ onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
+ getDialog().dismiss();
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ getCustomizablePreference().onDialogClosed(positiveResult);
+ final ListPreference preference = getCustomizablePreference();
+ final String value = getValue();
+ if (positiveResult && value != null) {
+ if (preference.callChangeListener(value)) {
+ preference.setValue(value);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 6f4a3a4..410d3d2 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -80,10 +80,8 @@
mTunerService = Dependency.get(TunerService.class);
mHandler = new Handler();
addPreferencesFromResource(R.xml.lockscreen_settings);
- setupGroup((PreferenceGroup) findPreference(KEY_LEFT), LOCKSCREEN_LEFT_BUTTON,
- LOCKSCREEN_LEFT_UNLOCK);
- setupGroup((PreferenceGroup) findPreference(KEY_RIGHT), LOCKSCREEN_RIGHT_BUTTON,
- LOCKSCREEN_RIGHT_UNLOCK);
+ setupGroup(LOCKSCREEN_LEFT_BUTTON, LOCKSCREEN_LEFT_UNLOCK);
+ setupGroup(LOCKSCREEN_RIGHT_BUTTON, LOCKSCREEN_RIGHT_UNLOCK);
}
@Override
@@ -92,30 +90,14 @@
mTunables.forEach(t -> mTunerService.removeTunable(t));
}
- private void setupGroup(PreferenceGroup group, String buttonSetting, String unlockKey) {
- SwitchPreference customize = (SwitchPreference) group.findPreference(KEY_CUSTOMIZE);
- Preference shortcut = group.findPreference(KEY_SHORTCUT);
- SwitchPreference unlock = (SwitchPreference) group.findPreference(unlockKey);
+ private void setupGroup(String buttonSetting, String unlockKey) {
+ Preference shortcut = findPreference(buttonSetting);
+ SwitchPreference unlock = (SwitchPreference) findPreference(unlockKey);
addTunable((k, v) -> {
- boolean visible = v != null;
- customize.setChecked(visible);
- shortcut.setVisible(visible);
+ boolean visible = !TextUtils.isEmpty(v);
unlock.setVisible(visible);
- if (visible) {
- setSummary(shortcut, v);
- }
+ setSummary(shortcut, v);
}, buttonSetting);
- customize.setOnPreferenceChangeListener((preference, newValue) -> {
- boolean hasSetting = mTunerService.getValue(buttonSetting) != null;
- if (hasSetting != (boolean) newValue) {
- mHandler.post(() -> mTunerService.setValue(buttonSetting, hasSetting ? null : ""));
- }
- return true;
- });
- shortcut.setOnPreferenceClickListener(preference -> {
- showSelectDialog(buttonSetting);
- return true;
- });
}
private void showSelectDialog(String buttonSetting) {
@@ -129,24 +111,15 @@
mTunerService.setValue(buttonSetting, item.getSettingValue());
dialog.dismiss();
});
- LauncherApps apps = getContext().getSystemService(LauncherApps.class);
- List<LauncherActivityInfo> activities = apps.getActivityList(null,
- Process.myUserHandle());
-
- activities.forEach(info -> {
- App app = new App(getContext(), info);
- try {
- new ShortcutParser(getContext(), info.getComponentName()).getShortcuts().forEach(
- shortcut -> app.addChild(new StaticShortcut(getContext(), shortcut)));
- } catch (NameNotFoundException e) {
- }
- adapter.addItem(app);
- });
v.setAdapter(adapter);
}
private void setSummary(Preference shortcut, String value) {
+ if (value == null) {
+ shortcut.setSummary(R.string.lockscreen_none);
+ return;
+ }
if (value.contains("::")) {
Shortcut info = getShortcutInfo(getContext(), value);
shortcut.setSummary(info != null ? info.label : null);
@@ -155,7 +128,7 @@
shortcut.setSummary(info != null ? info.loadLabel(getContext().getPackageManager())
: null);
} else {
- shortcut.setSummary(null);
+ shortcut.setSummary(R.string.lockscreen_none);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 28a0057..45abd45 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -33,6 +33,9 @@
import android.content.DialogInterface.OnClickListener;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -58,7 +61,7 @@
import java.util.ArrayList;
-public class NavBarTuner extends PreferenceFragment {
+public class NavBarTuner extends TunerPreferenceFragment {
private static final String LAYOUT = "layout";
private static final String LEFT = "left";
@@ -68,13 +71,13 @@
private static final String KEYCODE = "keycode";
private static final String ICON = "icon";
- private static final int[] ICONS = new int[]{
- R.drawable.ic_qs_circle,
- R.drawable.ic_add,
- R.drawable.ic_remove,
- R.drawable.ic_left,
- R.drawable.ic_right,
- R.drawable.ic_menu,
+ private static final int[][] ICONS = new int[][]{
+ {R.drawable.ic_qs_circle, R.string.tuner_circle},
+ {R.drawable.ic_add, R.string.tuner_plus},
+ {R.drawable.ic_remove, R.string.tuner_minus},
+ {R.drawable.ic_left, R.string.tuner_left},
+ {R.drawable.ic_right, R.string.tuner_right},
+ {R.drawable.ic_menu, R.string.tuner_menu},
};
private final ArrayList<Tunable> mTunables = new ArrayList<>();
@@ -96,10 +99,8 @@
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.nav_bar_tuner);
bindLayout((ListPreference) findPreference(LAYOUT));
- bindButton((PreferenceCategory) findPreference(LEFT),
- NAV_BAR_LEFT, NAVSPACE);
- bindButton((PreferenceCategory) findPreference(RIGHT),
- NAV_BAR_RIGHT, MENU_IME);
+ bindButton(NAV_BAR_LEFT, NAVSPACE, LEFT);
+ bindButton(NAV_BAR_RIGHT, MENU_IME, RIGHT);
}
@Override
@@ -129,9 +130,8 @@
});
}
- private void bindButton(PreferenceCategory parent, String setting, String def) {
- String k = parent.getKey();
- DropDownPreference type = (DropDownPreference) findPreference(TYPE + "_" + k);
+ private void bindButton(String setting, String def, String k) {
+ ListPreference type = (ListPreference) findPreference(TYPE + "_" + k);
Preference keycode = findPreference(KEYCODE + "_" + k);
ListPreference icon = (ListPreference) findPreference(ICON + "_" + k);
setupIcons(icon);
@@ -195,8 +195,14 @@
.loadDrawable(getContext());
d.setTint(Color.BLACK);
d.setBounds(0, 0, size, size);
- ImageSpan span = new ImageSpan(d);
+ ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
builder.append(" ", span, 0);
+ builder.append(" ");
+ for (int i = 0; i < ICONS.length; i++) {
+ if (ICONS[i][0] == id) {
+ builder.append(getString(ICONS[i][1]));
+ }
+ }
icon.setSummary(builder);
} catch (Exception e) {
Log.d("NavButton", "Problem with summary", e);
@@ -204,7 +210,7 @@
}
}
- private void setValue(String setting, DropDownPreference type, Preference keycode,
+ private void setValue(String setting, ListPreference type, Preference keycode,
ListPreference icon) {
String button = type.getValue();
if (KEY.equals(button)) {
@@ -226,14 +232,16 @@
getContext().getResources().getDisplayMetrics());
for (int i = 0; i < ICONS.length; i++) {
SpannableStringBuilder builder = new SpannableStringBuilder();
- Drawable d = Icon.createWithResource(getContext().getPackageName(), ICONS[i])
+ Drawable d = Icon.createWithResource(getContext().getPackageName(), ICONS[i][0])
.loadDrawable(getContext());
d.setTint(Color.BLACK);
d.setBounds(0, 0, size, size);
- ImageSpan span = new ImageSpan(d);
+ ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
builder.append(" ", span, 0);
+ builder.append(" ");
+ builder.append(getString(ICONS[i][1]));
labels[i] = builder;
- values[i] = getContext().getPackageName() + "/" + ICONS[i];
+ values[i] = getContext().getPackageName() + "/" + ICONS[i][0];
}
icon.setEntries(labels);
icon.setEntryValues(values);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
new file mode 100644
index 0000000..dc0d8bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toolbar;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.R;
+
+import libcore.util.Objects;
+
+public class RadioListPreference extends CustomListPreference {
+
+ private OnClickListener mOnClickListener;
+ private CharSequence mSummary;
+
+ public RadioListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(Builder builder, OnClickListener listener) {
+ mOnClickListener = listener;
+ }
+
+ @Override
+ public void setSummary(CharSequence summary) {
+ super.setSummary(summary);
+ mSummary = summary;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ if (mSummary == null || mSummary.toString().contains("%s")) {
+ return super.getSummary();
+ }
+ return mSummary;
+ }
+
+ @Override
+ protected Dialog onDialogCreated(DialogFragment fragment, Dialog dialog) {
+ Dialog d = new Dialog(getContext(), android.R.style.Theme_DeviceDefault_Settings);
+ Toolbar t = (Toolbar) d.findViewById(com.android.internal.R.id.action_bar);
+ View v = new View(getContext());
+ v.setId(R.id.content);
+ d.setContentView(v);
+ t.setTitle(getTitle());
+ t.setNavigationIcon(Utils.getDrawable(d.getContext(), android.R.attr.homeAsUpIndicator));
+ t.setNavigationOnClickListener(view -> d.dismiss());
+
+ RadioFragment f = new RadioFragment();
+ f.setPreference(this);
+ FragmentHostManager.get(v).getFragmentManager()
+ .beginTransaction()
+ .add(android.R.id.content, f)
+ .commit();
+ return d;
+ }
+
+ @Override
+ protected void onDialogStateRestored(DialogFragment fragment, Dialog dialog,
+ Bundle savedInstanceState) {
+ super.onDialogStateRestored(fragment, dialog, savedInstanceState);
+ View view = dialog.findViewById(R.id.content);
+ RadioFragment radioFragment = (RadioFragment) FragmentHostManager.get(view)
+ .getFragmentManager().findFragmentById(R.id.content);
+ if (radioFragment != null) {
+ radioFragment.setPreference(this);
+ }
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ super.onDialogClosed(positiveResult);
+ }
+
+ public static class RadioFragment extends TunerPreferenceFragment {
+ private RadioListPreference mListPref;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ Context context = getPreferenceManager().getContext();
+ PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(context);
+ setPreferenceScreen(screen);
+ if (mListPref != null) {
+ update();
+ }
+ }
+
+ private void update() {
+ Context context = getPreferenceManager().getContext();
+
+ CharSequence[] entries = mListPref.getEntries();
+ CharSequence[] values = mListPref.getEntryValues();
+ CharSequence current = mListPref.getValue();
+ for (int i = 0; i < entries.length; i++) {
+ CharSequence entry = entries[i];
+ SelectablePreference pref = new SelectablePreference(context);
+ getPreferenceScreen().addPreference(pref);
+ pref.setTitle(entry);
+ pref.setChecked(Objects.equal(current, values[i]));
+ pref.setKey(String.valueOf(i));
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ mListPref.mOnClickListener.onClick(null, Integer.parseInt(preference.getKey()));
+ return true;
+ }
+
+ public void setPreference(RadioListPreference radioListPreference) {
+ mListPref = radioListPreference;
+ if (getPreferenceManager() != null) {
+ update();
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/SelectablePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/SelectablePreference.java
new file mode 100644
index 0000000..1d15708
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/SelectablePreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.v7.preference.CheckBoxPreference;
+import android.util.TypedValue;
+
+import com.android.systemui.statusbar.ScalingDrawableWrapper;
+
+public class SelectablePreference extends CheckBoxPreference {
+ private final int mSize;
+
+ public SelectablePreference(Context context) {
+ super(context);
+ setWidgetLayoutResource(com.android.systemui.R.layout.preference_widget_radiobutton);
+ setSelectable(true);
+ mSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32,
+ context.getResources().getDisplayMetrics());
+ }
+
+ @Override
+ public void setIcon(Drawable icon) {
+ super.setIcon(new ScalingDrawableWrapper(icon,
+ mSize / (float) icon.getIntrinsicWidth()));
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ShortcutPicker.java b/packages/SystemUI/src/com/android/systemui/tuner/ShortcutPicker.java
new file mode 100644
index 0000000..533388a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ShortcutPicker.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
+
+import android.content.Context;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Process;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.tuner.ShortcutParser.Shortcut;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ShortcutPicker extends PreferenceFragment implements Tunable {
+
+ private final ArrayList<SelectablePreference> mSelectablePreferences = new ArrayList<>();
+ private String mKey;
+ private SelectablePreference mNonePreference;
+ private TunerService mTunerService;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ Context context = getPreferenceManager().getContext();
+ PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(context);
+ screen.setOrderingAsAdded(true);
+ PreferenceCategory otherApps = new PreferenceCategory(context);
+ otherApps.setTitle(R.string.tuner_other_apps);
+
+ mNonePreference = new SelectablePreference(context);
+ mSelectablePreferences.add(mNonePreference);
+ mNonePreference.setTitle(R.string.lockscreen_none);
+ mNonePreference.setIcon(R.drawable.ic_remove_circle);
+ screen.addPreference(mNonePreference);
+
+ LauncherApps apps = getContext().getSystemService(LauncherApps.class);
+ List<LauncherActivityInfo> activities = apps.getActivityList(null,
+ Process.myUserHandle());
+
+ screen.addPreference(otherApps);
+ activities.forEach(info -> {
+ try {
+ List<Shortcut> shortcuts = new ShortcutParser(getContext(),
+ info.getComponentName()).getShortcuts();
+ AppPreference appPreference = new AppPreference(context, info);
+ mSelectablePreferences.add(appPreference);
+ if (shortcuts.size() != 0) {
+ //PreferenceCategory category = new PreferenceCategory(context);
+ //screen.addPreference(category);
+ //category.setTitle(info.getLabel());
+ screen.addPreference(appPreference);
+ shortcuts.forEach(shortcut -> {
+ ShortcutPreference shortcutPref = new ShortcutPreference(context, shortcut,
+ info.getLabel());
+ mSelectablePreferences.add(shortcutPref);
+ screen.addPreference(shortcutPref);
+ });
+ return;
+ }
+ otherApps.addPreference(appPreference);
+ } catch (NameNotFoundException e) {
+ }
+ });
+ // Move other apps to the bottom.
+ screen.removePreference(otherApps);
+ for (int i = 0; i < otherApps.getPreferenceCount(); i++) {
+ Preference p = otherApps.getPreference(0);
+ otherApps.removePreference(p);
+ p.setOrder(Preference.DEFAULT_ORDER);
+ screen.addPreference(p);
+ }
+ //screen.addPreference(otherApps);
+
+ setPreferenceScreen(screen);
+ mKey = getArguments().getString(ARG_PREFERENCE_ROOT);
+ mTunerService = Dependency.get(TunerService.class);
+ mTunerService.addTunable(this, mKey);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ mTunerService.setValue(mKey, preference.toString());
+ getActivity().onBackPressed();
+ return true;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (LOCKSCREEN_LEFT_BUTTON.equals(mKey)) {
+ getActivity().setTitle(R.string.lockscreen_shortcut_left);
+ } else {
+ getActivity().setTitle(R.string.lockscreen_shortcut_right);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mTunerService.removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ String v = newValue != null ? newValue : "";
+ mSelectablePreferences.forEach(p -> p.setChecked(v.equals(p.toString())));
+ }
+
+ private static class AppPreference extends SelectablePreference {
+ private final LauncherActivityInfo mInfo;
+ private boolean mBinding;
+
+ public AppPreference(Context context, LauncherActivityInfo info) {
+ super(context);
+ mInfo = info;
+ setTitle(context.getString(R.string.tuner_launch_app, info.getLabel()));
+ setSummary(context.getString(R.string.tuner_app, info.getLabel()));
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ mBinding = true;
+ if (getIcon() == null) {
+ setIcon(mInfo.getBadgedIcon(
+ getContext().getResources().getConfiguration().densityDpi));
+ }
+ mBinding = false;
+ super.onBindViewHolder(holder);
+ }
+
+ @Override
+ protected void notifyChanged() {
+ if (mBinding) return;
+ super.notifyChanged();
+ }
+
+ @Override
+ public String toString() {
+ return mInfo.getComponentName().flattenToString();
+ }
+ }
+
+ private static class ShortcutPreference extends SelectablePreference {
+ private final Shortcut mShortcut;
+ private boolean mBinding;
+
+ public ShortcutPreference(Context context, Shortcut shortcut, CharSequence appLabel) {
+ super(context);
+ mShortcut = shortcut;
+ setTitle(shortcut.label);
+ setSummary(context.getString(R.string.tuner_app, appLabel));
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ mBinding = true;
+ if (getIcon() == null) {
+ setIcon(mShortcut.icon.loadDrawable(getContext()));
+ }
+ mBinding = false;
+ super.onBindViewHolder(holder);
+ }
+
+ @Override
+ protected void notifyChanged() {
+ if (mBinding) return;
+ super.notifyChanged();
+ }
+
+ @Override
+ public String toString() {
+ return mShortcut.toString();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 74280a3..4eb1db6 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -22,10 +22,12 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
+import android.view.MenuItem;
import com.android.settingslib.drawer.SettingsDrawerActivity;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.fragments.FragmentService;
public class TunerActivity extends SettingsDrawerActivity implements
PreferenceFragment.OnPreferenceStartFragmentCallback,
@@ -51,6 +53,22 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ Dependency.destroy(FragmentService.class, s -> s.destroyAll());
+ Dependency.clearDependencies();
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onMenuItemSelected(featureId, item);
+ }
+
+ @Override
public void onBackPressed() {
if (!getFragmentManager().popBackStackImmediate()) {
super.onBackPressed();
@@ -62,6 +80,9 @@
try {
Class<?> cls = Class.forName(pref.getFragment());
Fragment fragment = (Fragment) cls.newInstance();
+ final Bundle b = new Bundle(1);
+ b.putString(PreferenceFragment.ARG_PREFERENCE_ROOT, pref.getKey());
+ fragment.setArguments(b);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
setTitle(pref.getTitle());
transaction.replace(R.id.content_frame, fragment);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerPreferenceFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerPreferenceFragment.java
new file mode 100644
index 0000000..06d40da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerPreferenceFragment.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+
+public abstract class TunerPreferenceFragment extends PreferenceFragment {
+
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+ DialogFragment f = null;
+ if (preference instanceof CustomListPreference) {
+ f = CustomListPreference.CustomListPreferenceDialogFragment
+ .newInstance(preference.getKey());
+ } else {
+ super.onDisplayPreferenceDialog(preference);
+ }
+ f.setTargetFragment(this, 0);
+ f.show(getFragmentManager(), "dialog_preference");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 4146cb81..70c7d3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -18,26 +18,32 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
import android.content.ComponentName;
-import android.content.Context;
import android.os.Looper;
import android.service.quicksettings.Tile;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysUIRunner;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import java.util.ArrayList;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.utils.TestableLooper;
+import com.android.systemui.utils.TestableLooper.RunWithLooper;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import java.util.ArrayList;
+
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(SysUIRunner.class)
+@RunWithLooper(setAsMainLooper = true)
public class TileServicesTest extends SysuiTestCase {
private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
@@ -46,16 +52,24 @@
@Before
public void setUp() throws Exception {
+ TestableLooper.get(this).setAsMainLooper();
mManagers = new ArrayList<>();
- QSTileHost host = new QSTileHost(mContext, null, null);
+ QSTileHost host = new QSTileHost(mContext, null,
+ mock(StatusBarIconController.class));
mTileService = new TestTileServices(host, Looper.getMainLooper());
}
+ @After
+ public void tearDown() throws Exception {
+ mTileService.getHost().destroy();
+ TestableLooper.get(this).processAllMessages();
+ }
+
@Test
public void testRecalculateBindAllowance() {
// Add some fake tiles.
for (int i = 0; i < NUM_FAKES; i++) {
- mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ mTileService.getTileWrapper(mock(CustomTile.class));
}
assertEquals(NUM_FAKES, mManagers.size());
@@ -91,7 +105,7 @@
@Test
public void testCalcFew() {
for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
- mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ mTileService.getTileWrapper(mock(CustomTile.class));
}
mTileService.recalculateBindAllowance();
@@ -115,7 +129,7 @@
@Override
protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
- TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+ TileServiceManager manager = mock(TileServiceManager.class);
mManagers.add(manager);
return manager;
}
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 14abb53..40499c9 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -351,7 +351,7 @@
}
public List<R> queryIntentFromList(Intent intent, String resolvedType, boolean defaultOnly,
- boolean visibleToEphemeral, boolean isEphemeral, ArrayList<F[]> listCut, int userId) {
+ ArrayList<F[]> listCut, int userId) {
ArrayList<R> resultList = new ArrayList<R>();
final boolean debug = localLOGV ||
@@ -361,8 +361,8 @@
final String scheme = intent.getScheme();
int N = listCut.size();
for (int i = 0; i < N; ++i) {
- buildResolveList(intent, categories, debug, defaultOnly, visibleToEphemeral,
- isEphemeral, resolvedType, scheme, listCut.get(i), resultList, userId);
+ buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme,
+ listCut.get(i), resultList, userId);
}
filterResults(resultList);
sortResults(resultList);
@@ -370,7 +370,7 @@
}
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
- boolean visibleToEphemeral, boolean isEphemeral, int userId) {
+ int userId) {
String scheme = intent.getScheme();
ArrayList<R> finalList = new ArrayList<R>();
@@ -443,20 +443,20 @@
FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
if (firstTypeCut != null) {
- buildResolveList(intent, categories, debug, defaultOnly, visibleToEphemeral,
- isEphemeral, resolvedType, scheme, firstTypeCut, finalList, userId);
+ buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
+ scheme, firstTypeCut, finalList, userId);
}
if (secondTypeCut != null) {
- buildResolveList(intent, categories, debug, defaultOnly, visibleToEphemeral,
- isEphemeral, resolvedType, scheme, secondTypeCut, finalList, userId);
+ buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
+ scheme, secondTypeCut, finalList, userId);
}
if (thirdTypeCut != null) {
- buildResolveList(intent, categories, debug, defaultOnly, visibleToEphemeral,
- isEphemeral, resolvedType, scheme, thirdTypeCut, finalList, userId);
+ buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
+ scheme, thirdTypeCut, finalList, userId);
}
if (schemeCut != null) {
- buildResolveList(intent, categories, debug, defaultOnly, visibleToEphemeral,
- isEphemeral, resolvedType, scheme, schemeCut, finalList, userId);
+ buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
+ scheme, schemeCut, finalList, userId);
}
filterResults(finalList);
sortResults(finalList);
@@ -694,8 +694,8 @@
}
private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
- boolean debug, boolean defaultOnly, boolean visibleToEphemeral, boolean isEphemeral,
- String resolvedType, String scheme, F[] src, List<R> dest, int userId) {
+ boolean debug, boolean defaultOnly, String resolvedType, String scheme,
+ F[] src, List<R> dest, int userId) {
final String action = intent.getAction();
final Uri data = intent.getData();
final String packageName = intent.getPackage();
@@ -735,15 +735,6 @@
continue;
}
- // throw out filters that aren't visible to ephemeral apps
- if (visibleToEphemeral && !filter.isVisibleToEphemeral()) {
- continue;
- }
- // throw out ephemeral filters if we're not explicitly requesting them
- if (!isEphemeral && filter.isEphemeral()) {
- continue;
- }
-
// Are we verified ?
if (filter.getAutoVerify()) {
if (localVerificationLOGV || debug) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a73eb18..d9123f4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -293,6 +293,7 @@
import android.service.voice.VoiceInteractionManagerInternal;
import android.service.voice.VoiceInteractionSession;
import android.telecom.TelecomManager;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.text.style.SuggestionSpan;
@@ -3776,6 +3777,11 @@
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
+ // the per-user SELinux context must be set
+ if (TextUtils.isEmpty(app.info.seInfoUser)) {
+ throw new IllegalStateException("SELinux tag not defined");
+ }
+ final String seInfo = app.info.seInfo + app.info.seInfoUser;
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
@@ -3787,12 +3793,12 @@
if (hostingType.equals("webview_service")) {
startResult = Process.startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
checkTime(startTime, "startProcess: returned from zygote!");
@@ -3808,7 +3814,7 @@
try {
AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
- app.info.seinfo, app.info.sourceDir, startResult.pid);
+ seInfo, app.info.sourceDir, startResult.pid);
} catch (RemoteException ex) {
// Ignore
}
@@ -18774,8 +18780,7 @@
}
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
- resolvedType, false, false /*visibleToEphemeral*/,
- false /*isInstant*/, users[i]);
+ resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
@@ -18784,8 +18789,7 @@
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
- resolvedType, false, false /*visibleToEphemeral*/,
- false /*isInstant*/, userId);
+ resolvedType, false /*defaultOnly*/, userId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 95734a4..2f84486 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1196,7 +1196,7 @@
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
try {
return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY | flags
+ PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
| ActivityManagerService.STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index 93c14b9..376a864 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -151,8 +151,7 @@
// For the first pass, find all the rules that have at least one intent-filter or
// component-filter that matches this intent
List<Rule> candidateRules;
- candidateRules = resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/,
- false /*visibleToEphemeral*/, false /*isInstant*/, 0);
+ candidateRules = resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, 0);
if (candidateRules == null) {
candidateRules = new ArrayList<Rule>();
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 67acdaf..f2b5564 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3887,14 +3887,18 @@
private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
final String canceledKey = r.getKey();
- // Remove from either list
- boolean wasPosted;
- if (mNotificationList.remove(r)) {
- mNotificationsByKey.remove(r.sbn.getKey());
+ // Remove from both lists, either list could have a separate Record for what is effectively
+ // the same notification.
+ boolean wasPosted = false;
+ NotificationRecord recordInList = null;
+ if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) != null) {
+ mNotificationList.remove(recordInList);
+ mNotificationsByKey.remove(recordInList.sbn.getKey());
wasPosted = true;
- } else {
- mEnqueuedNotifications.remove(r);
- wasPosted = false;
+ }
+ if ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
+ != null) {
+ mEnqueuedNotifications.remove(recordInList);
}
// Record caller.
@@ -4322,17 +4326,12 @@
// TODO: need to combine a bunch of these getters with slightly different behavior.
// TODO: Should enqueuing just add to mNotificationsByKey instead?
private NotificationRecord findNotificationByKeyLocked(String key) {
- final int N = mNotificationList.size();
- for (int i = 0; i < N; i++) {
- if (key.equals(mNotificationList.get(i).getKey())) {
- return mNotificationList.get(i);
- }
+ NotificationRecord r;
+ if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
+ return r;
}
- final int M = mEnqueuedNotifications.size();
- for (int i = 0; i < M; i++) {
- if (key.equals(mEnqueuedNotifications.get(i).getKey())) {
- return mEnqueuedNotifications.get(i);
- }
+ if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
+ return r;
}
return null;
}
@@ -4350,8 +4349,7 @@
}
private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
- String pkg, String tag, int id, int userId)
- {
+ String pkg, String tag, int id, int userId) {
final int len = list.size();
for (int i = 0; i < len; i++) {
NotificationRecord r = list.get(i);
@@ -4363,6 +4361,18 @@
return null;
}
+ private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
+ String key)
+ {
+ final int N = list.size();
+ for (int i = 0; i < N; i++) {
+ if (key.equals(list.get(i).getKey())) {
+ return list.get(i);
+ }
+ }
+ return null;
+ }
+
// lock on mNotificationList
int indexOfNotificationLocked(String key) {
final int N = mNotificationList.size();
diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java
index 3c55422..d99a1b6 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolver.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolver.java
@@ -234,8 +234,7 @@
}
}
List<EphemeralResponse> matchedResolveInfoList = ephemeralResolver.queryIntent(
- intent, resolvedType, false /*defaultOnly*/, false /*visibleToEphemeral*/,
- false /*isInstant*/, userId);
+ intent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
return matchedResolveInfoList.get(0);
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 42934a4..23925ad 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -217,7 +217,7 @@
propagateInstantAppPermissionsIfNeeded(pkg.packageName, userId);
// Track instant apps
- if (pkg.applicationInfo.isInstantApp()) {
+ if (ps.getInstantApp(userId)) {
addInstantAppLPw(userId, ps.appId);
}
@@ -257,7 +257,7 @@
continue;
}
- if (pkg.applicationInfo.isInstantApp()) {
+ if (ps.getInstantApp(userId)) {
// Add a record for an uninstalled instant app
addUninstalledInstantAppLPw(pkg, userId);
removeInstantAppLPw(userId, ps.appId);
@@ -533,11 +533,12 @@
final int packageCount = mService.mPackages.size();
for (int i = 0; i < packageCount; i++) {
- PackageParser.Package pkg = mService.mPackages.valueAt(i);
- if (!pkg.applicationInfo.isInstantApp()) {
+ final PackageParser.Package pkg = mService.mPackages.valueAt(i);
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null || !ps.getInstantApp(userId)) {
continue;
}
- InstantAppInfo info = createInstantAppInfoForPackage(
+ final InstantAppInfo info = createInstantAppInfoForPackage(
pkg, userId, true);
if (info == null) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index efd3132..0df4570 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -683,9 +683,9 @@
File stageDir = null;
String stageCid = null;
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- final boolean isEphemeral =
- (params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
- stageDir = buildStageDir(params.volumeUuid, sessionId, isEphemeral);
+ final boolean isInstant =
+ (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
} else {
stageCid = buildExternalStageCid(sessionId);
}
@@ -787,9 +787,6 @@
}
private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
- if (isEphemeral) {
- return Environment.getDataAppEphemeralDirectory(volumeUuid);
- }
return Environment.getDataAppDirectory(volumeUuid);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 067a136..463cfac 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -704,7 +704,7 @@
final ApkLite apk;
try {
int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
- if ((params.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
+ if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
flags |= PackageParser.PARSE_IS_EPHEMERAL;
}
apk = PackageParser.parseApkLite(addedFile, flags);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0d63f72..8ef472e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -41,7 +41,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
-import static android.content.pm.PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
@@ -164,6 +164,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
@@ -421,8 +422,11 @@
static final int SCAN_CHECK_ONLY = 1<<13;
static final int SCAN_DONT_KILL_APP = 1<<14;
static final int SCAN_IGNORE_FROZEN = 1<<15;
- static final int REMOVE_CHATTY = 1<<16;
- static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<17;
+ static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<16;
+ static final int SCAN_AS_INSTANT_APP = 1<<17;
+ static final int SCAN_AS_FULL_APP = 1<<18;
+ /** Should not be with the scan flags */
+ static final int FLAGS_REMOVE_CHATTY = 1<<31;
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
@@ -626,7 +630,6 @@
/** Directory where installed third-party apps stored */
final File mAppInstallDir;
- final File mEphemeralInstallDir;
/**
* Directory to which applications installed internally have their
@@ -1779,28 +1782,32 @@
// the first time vs. those who are seeing an update.
int[] firstUsers = EMPTY_INT_ARRAY;
int[] updateUsers = EMPTY_INT_ARRAY;
- if (res.origUsers == null || res.origUsers.length == 0) {
- firstUsers = res.newUsers;
- } else {
- for (int newUser : res.newUsers) {
- boolean isNew = true;
- for (int origUser : res.origUsers) {
- if (origUser == newUser) {
- isNew = false;
- break;
- }
+ final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
+ final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
+ for (int newUser : res.newUsers) {
+ if (ps.getInstantApp(newUser)) {
+ continue;
+ }
+ if (allNewUsers) {
+ firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ continue;
+ }
+ boolean isNew = true;
+ for (int origUser : res.origUsers) {
+ if (origUser == newUser) {
+ isNew = false;
+ break;
}
- if (isNew) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
- } else {
- updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
- }
+ }
+ if (isNew) {
+ firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ } else {
+ updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
}
}
- // Send installed broadcasts if the install/update is not ephemeral
- // and the package is not a static shared lib.
- if (!isEphemeral(res.pkg) && res.pkg.staticSharedLibName == null) {
+ // Send installed broadcasts if the package is not a static shared lib.
+ if (res.pkg.staticSharedLibName == null) {
mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
// Send added for users that see the package for the first time
@@ -1887,16 +1894,14 @@
}
}
- if (!isEphemeral(res.pkg)) {
- // Notify DexManager that the package was installed for new users.
- // The updated users should already be indexed and the package code paths
- // should not change.
- // Don't notify the manager for ephemeral apps as they are not expected to
- // survive long enough to benefit of background optimizations.
- for (int userId : firstUsers) {
- PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
- mDexManager.notifyPackageInstalled(info, userId);
- }
+ // Notify DexManager that the package was installed for new users.
+ // The updated users should already be indexed and the package code paths
+ // should not change.
+ // Don't notify the manager for ephemeral apps as they are not expected to
+ // survive long enough to benefit of background optimizations.
+ for (int userId : firstUsers) {
+ PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
+ mDexManager.notifyPackageInstalled(info, userId);
}
}
@@ -2285,7 +2290,6 @@
File dataDir = Environment.getDataDirectory();
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
- mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
@@ -2589,10 +2593,6 @@
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
- scanDirLI(mEphemeralInstallDir, mDefParseFlags
- | PackageParser.PARSE_IS_EPHEMERAL,
- scanFlags | SCAN_REQUIRE_KNOWN, 0);
-
/**
* Remove disable package settings for any updated system
* apps that were removed via an OTA. If they're not a
@@ -3335,14 +3335,14 @@
&& callingAppId != Process.ROOT_UID
&& checkUidPermission(Manifest.permission.ACCESS_INSTANT_APPS,
Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) {
- final String ephemeralPackageName = getEphemeralPackageName(Binder.getCallingUid());
- if (ephemeralPackageName != null) {
+ final String instantAppPackageName = getInstantAppPackageName(Binder.getCallingUid());
+ if (instantAppPackageName != null) {
// ephemeral apps can only get information on themselves
- if (!ephemeralPackageName.equals(p.packageName)) {
+ if (!instantAppPackageName.equals(p.packageName)) {
return null;
}
} else {
- if (p.applicationInfo.isInstantApp()) {
+ if (ps.getInstantApp(userId)) {
// only get access to the ephemeral app if we've been granted access
if (!mInstantAppRegistry.isInstantAccessGranted(
userId, callingAppId, ps.appId)) {
@@ -3953,17 +3953,17 @@
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
final int callingUid = Binder.getCallingUid();
- if (callingUid == Process.SYSTEM_UID || callingUid == 0) {
- // The system sees all components
- flags |= PackageManager.MATCH_EPHEMERAL;
- } else if (getEphemeralPackageName(callingUid) != null) {
+ if (getInstantAppPackageName(callingUid) != null) {
// But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
- flags |= PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY;
- flags |= PackageManager.MATCH_EPHEMERAL;
+ flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
+ flags |= PackageManager.MATCH_INSTANT;
} else {
// Otherwise, prevent leaking ephemeral components
- flags &= ~PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY;
- flags &= ~PackageManager.MATCH_EPHEMERAL;
+ flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ // Unless called from the system process
+ flags &= ~PackageManager.MATCH_INSTANT;
+ }
}
return updateFlagsForComponent(flags, userId, cookie);
}
@@ -4692,7 +4692,8 @@
return;
}
- if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps.getInstantApp(userId) && !bp.isInstant()) {
throw new SecurityException("Cannot grant non-ephemeral permission"
+ name + " for package " + packageName);
}
@@ -5741,8 +5742,7 @@
List<PersistentPreferredActivity> pprefs = ppir != null
? ppir.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0,
- (flags & PackageManager.MATCH_EPHEMERAL) != 0, userId)
+ userId)
: null;
if (pprefs != null && pprefs.size() > 0) {
final int M = pprefs.size();
@@ -5814,8 +5814,7 @@
List<PreferredActivity> prefs = pir != null
? pir.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0,
- (flags & PackageManager.MATCH_EPHEMERAL) != 0, userId)
+ userId)
: null;
if (prefs != null && prefs.size() > 0) {
boolean changed = false;
@@ -5986,8 +5985,7 @@
String resolvedType, int userId) {
CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
if (resolver != null) {
- return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/,
- false /*visibleToEphemeral*/, false /*isInstant*/, userId);
+ return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
}
return null;
}
@@ -6006,16 +6004,17 @@
}
/**
- * Returns the package name of the calling Uid if it's an ephemeral app. If it isn't
- * ephemeral, returns {@code null}.
+ * Returns the package name of the calling Uid if it's an instant app. If it isn't
+ * instant, returns {@code null}.
*/
- private String getEphemeralPackageName(int callingUid) {
+ private String getInstantAppPackageName(int callingUid) {
final int appId = UserHandle.getAppId(callingUid);
synchronized (mPackages) {
final Object obj = mSettings.getUserIdLPr(appId);
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- return ps.pkg.applicationInfo.isInstantApp() ? ps.pkg.packageName : null;
+ final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
+ return isInstantApp ? ps.pkg.packageName : null;
}
}
return null;
@@ -6024,7 +6023,7 @@
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- final String ephemeralPkgName = getEphemeralPackageName(Binder.getCallingUid());
+ final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
@@ -6046,14 +6045,14 @@
// an ephemeral application or 2) the calling package is ephemeral and the
// activity is not visible to ephemeral applications.
boolean matchEphemeral =
- (flags & PackageManager.MATCH_EPHEMERAL) != 0;
+ (flags & PackageManager.MATCH_INSTANT) != 0;
boolean ephemeralVisibleOnly =
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0;
+ (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
boolean blockResolution =
- (!matchEphemeral && ephemeralPkgName == null
+ (!matchEphemeral && instantAppPkgName == null
&& (ai.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0)
- || (ephemeralVisibleOnly && ephemeralPkgName != null
+ & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0)
+ || (ephemeralVisibleOnly && instantAppPkgName != null
&& (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0);
if (!blockResolution) {
final ResolveInfo ri = new ResolveInfo();
@@ -6080,7 +6079,7 @@
List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
xpResult.add(xpResolveInfo);
return filterForEphemeral(
- filterIfNotSystemUser(xpResult, userId), ephemeralPkgName);
+ filterIfNotSystemUser(xpResult, userId), instantAppPkgName);
}
// Check for results in the current profile.
@@ -6120,13 +6119,13 @@
// And we are not going to add emphemeral app, so we can return the
// result straight away.
result.add(xpDomainInfo.resolveInfo);
- return filterForEphemeral(result, ephemeralPkgName);
+ return filterForEphemeral(result, instantAppPkgName);
}
} else if (result.size() <= 1 && !addEphemeral) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add emphemeral app, so we can return the result without
// further processing.
- return filterForEphemeral(result, ephemeralPkgName);
+ return filterForEphemeral(result, instantAppPkgName);
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
@@ -6140,7 +6139,7 @@
result = filterForEphemeral(filterIfNotSystemUser(
mActivities.queryIntentForPackage(
intent, resolvedType, flags, pkg.activities, userId),
- userId), ephemeralPkgName);
+ userId), instantAppPkgName);
} else {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
@@ -6178,7 +6177,7 @@
if (sortResult) {
Collections.sort(result, mResolvePrioritySorter);
}
- return filterForEphemeral(result, ephemeralPkgName);
+ return filterForEphemeral(result, instantAppPkgName);
}
private static class CrossProfileDomainInfo {
@@ -7142,9 +7141,9 @@
return false;
}
synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null) {
- return pkg.applicationInfo.isInstantApp();
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ return ps.getInstantApp(userId);
}
}
return false;
@@ -7647,7 +7646,7 @@
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
- final int policyFlags, int scanFlags, long currentTime, UserHandle user)
+ final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
@@ -7687,7 +7686,7 @@
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
- int policyFlags, int scanFlags, long currentTime, UserHandle user)
+ int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
PackageSetting ps = null;
PackageSetting updatedPkg;
@@ -7923,6 +7922,11 @@
pkg.setApplicationInfoBaseResourcePath(baseResourcePath);
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+ final int userId = ((user == null) ? 0 : user.getIdentifier());
+ if (ps != null && ps.getInstantApp(userId)) {
+ scanFlags |= SCAN_AS_INSTANT_APP;
+ }
+
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
@@ -8860,7 +8864,7 @@
}
private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
- final int policyFlags, int scanFlags, long currentTime, UserHandle user)
+ final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
// If the package has children and this is the first dive in the function
@@ -8899,7 +8903,8 @@
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ int scanFlags, long currentTime, @Nullable UserHandle user)
+ throws PackageManagerException {
boolean success = false;
try {
final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
@@ -8965,7 +8970,7 @@
}
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
- final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
+ final int policyFlags, final int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
@@ -9103,16 +9108,16 @@
if (pkgSetting == null) {
final String parentPackageName = (pkg.parentPackage != null)
? pkg.parentPackage.packageName : null;
-
+ final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
// REMOVE SharedUserSetting from method; update in a separate call
pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
- true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames(),
- UserManagerService.getInstance(), usesStaticLibraries,
- pkg.usesStaticLibrariesVersions);
+ true /*allowInstall*/, instantApp, parentPackageName,
+ pkg.getChildPackageNames(), UserManagerService.getInstance(),
+ usesStaticLibraries, pkg.usesStaticLibrariesVersions);
// SIDE EFFECTS; updates system state; move elsewhere
if (origPackage != null) {
mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
@@ -9179,9 +9184,8 @@
}
if (mFoundPolicyFile) {
- SELinuxMMAC.assignSeinfoValue(pkg);
+ SELinuxMMAC.assignSeInfoValue(pkg);
}
-
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
@@ -9416,11 +9420,11 @@
}
}
} else {
+ final int userId = user == null ? 0 : user.getIdentifier();
// Modify state for the given package setting
commitPackageSettings(pkg, pkgSetting, user, scanFlags,
(policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
- if (isEphemeral(pkg)) {
- final int userId = user == null ? 0 : user.getIdentifier();
+ if (pkgSetting.getInstantApp(userId)) {
mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
}
@@ -9535,10 +9539,10 @@
"Packages declaring static-shared libs must target O SDK or higher");
}
- // Package declaring static a shared lib cannot be ephemeral
- if (pkg.applicationInfo.isInstantApp()) {
+ // Package declaring static a shared lib cannot be instant apps
+ if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
throw new PackageManagerException(
- "Packages declaring static-shared libs cannot be ephemeral");
+ "Packages declaring static-shared libs cannot be instant apps");
}
// Package declaring static a shared lib cannot be renamed since the package
@@ -9781,7 +9785,6 @@
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
mAndroidApplication = pkg.applicationInfo;
-
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
@@ -10070,10 +10073,10 @@
PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
final String curPackageName = cur == null ? null : cur.info.packageName;
// Dont allow ephemeral apps to define new permission groups.
- if (pkg.applicationInfo.isInstantApp()) {
+ if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName
- + " ignored: ephemeral apps cannot define new permission groups.");
+ + " ignored: instant apps cannot define new permission groups.");
continue;
}
final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
@@ -10115,10 +10118,10 @@
PackageParser.Permission p = pkg.permissions.get(i);
// Dont allow ephemeral apps to define new permissions.
- if (pkg.applicationInfo.isInstantApp()) {
+ if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName
- + " ignored: ephemeral apps cannot define new permissions.");
+ + " ignored: instant apps cannot define new permissions.");
continue;
}
@@ -11740,13 +11743,10 @@
final class ActivityIntentResolver
extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, boolean visibleToEphemeral, boolean isEphemeral, int userId) {
+ boolean defaultOnly, int userId) {
if (!sUserManager.exists(userId)) return null;
- mFlags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0)
- | (visibleToEphemeral ? PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY : 0)
- | (isEphemeral ? PackageManager.MATCH_EPHEMERAL : 0);
- return super.queryIntent(intent, resolvedType, defaultOnly, visibleToEphemeral,
- isEphemeral, userId);
+ mFlags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0);
+ return super.queryIntent(intent, resolvedType, defaultOnly, userId);
}
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
@@ -11755,8 +11755,7 @@
mFlags = flags;
return super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0,
- (flags & PackageManager.MATCH_EPHEMERAL) != 0, userId);
+ userId);
}
public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
@@ -11767,9 +11766,6 @@
}
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final boolean vislbleToEphemeral =
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0;
- final boolean isEphemeral = (flags & PackageManager.MATCH_EPHEMERAL) != 0;
final int N = packageActivities.size();
ArrayList<PackageParser.ActivityIntentInfo[]> listCut =
new ArrayList<PackageParser.ActivityIntentInfo[]>(N);
@@ -11784,8 +11780,7 @@
listCut.add(array);
}
}
- return super.queryIntentFromList(intent, resolvedType, defaultOnly,
- vislbleToEphemeral, isEphemeral, listCut, userId);
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
/**
@@ -12197,11 +12192,24 @@
if (ps == null) {
return null;
}
+ final PackageUserState userState = ps.readUserState(userId);
ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,
- ps.readUserState(userId), userId);
+ userState, userId);
if (ai == null) {
return null;
}
+ final boolean matchVisibleToInstantApp =
+ (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
+ final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
+ // throw out filters that aren't visible to ephemeral apps
+ if (matchVisibleToInstantApp
+ && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+ return null;
+ }
+ // throw out ephemeral filters if we're not explicitly requesting them
+ if (!isInstantApp && userState.instantApp) {
+ return null;
+ }
final ResolveInfo res = new ResolveInfo();
res.activityInfo = ai;
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
@@ -12270,10 +12278,9 @@
private final class ServiceIntentResolver
extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, boolean visibleToEphemeral, boolean isEphemeral, int userId) {
+ boolean defaultOnly, int userId) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(intent, resolvedType, defaultOnly, visibleToEphemeral,
- isEphemeral, userId);
+ return super.queryIntent(intent, resolvedType, defaultOnly, userId);
}
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
@@ -12282,8 +12289,7 @@
mFlags = flags;
return super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0,
- (flags & PackageManager.MATCH_EPHEMERAL) != 0, userId);
+ userId);
}
public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
@@ -12294,9 +12300,6 @@
}
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final boolean vislbleToEphemeral =
- (flags&PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0;
- final boolean isEphemeral = (flags&PackageManager.MATCH_EPHEMERAL) != 0;
final int N = packageServices.size();
ArrayList<PackageParser.ServiceIntentInfo[]> listCut =
new ArrayList<PackageParser.ServiceIntentInfo[]>(N);
@@ -12311,8 +12314,7 @@
listCut.add(array);
}
}
- return super.queryIntentFromList(intent, resolvedType, defaultOnly,
- vislbleToEphemeral, isEphemeral, listCut, userId);
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
public final void addService(PackageParser.Service s) {
@@ -12487,10 +12489,9 @@
private final class ProviderIntentResolver
extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, boolean visibleToEphemeral, boolean isEphemeral, int userId) {
+ boolean defaultOnly, int userId) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(intent, resolvedType, defaultOnly, visibleToEphemeral,
- isEphemeral, userId);
+ return super.queryIntent(intent, resolvedType, defaultOnly, userId);
}
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
@@ -12500,8 +12501,7 @@
mFlags = flags;
return super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- (flags & PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0,
- (flags & PackageManager.MATCH_EPHEMERAL) != 0, userId);
+ userId);
}
public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
@@ -12513,9 +12513,6 @@
}
mFlags = flags;
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final boolean isEphemeral = (flags&PackageManager.MATCH_EPHEMERAL) != 0;
- final boolean vislbleToEphemeral =
- (flags&PackageManager.MATCH_VISIBLE_TO_EPHEMERAL_ONLY) != 0;
final int N = packageProviders.size();
ArrayList<PackageParser.ProviderIntentInfo[]> listCut =
new ArrayList<PackageParser.ProviderIntentInfo[]>(N);
@@ -12530,8 +12527,7 @@
listCut.add(array);
}
}
- return super.queryIntentFromList(intent, resolvedType, defaultOnly,
- vislbleToEphemeral, isEphemeral, listCut, userId);
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
public final void addProvider(PackageParser.Provider p) {
@@ -13072,7 +13068,7 @@
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
if (DEBUG_EPHEMERAL) {
- if ((sessionParams.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
+ if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + packageName);
}
}
@@ -13287,7 +13283,8 @@
* @hide
*/
@Override
- public int installExistingPackageAsUser(String packageName, int userId, int installReason) {
+ public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+ int installReason) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
null);
PackageSetting pkgSetting;
@@ -13302,6 +13299,10 @@
long callingId = Binder.clearCallingIdentity();
try {
boolean installed = false;
+ final boolean instantApp =
+ (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ final boolean fullApp =
+ (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
// writer
synchronized (mPackages) {
@@ -13316,7 +13317,11 @@
mSettings.writePackageRestrictionsLPr(userId);
mSettings.writeKernelMappingLPr(pkgSetting);
installed = true;
+ } else if (fullApp && pkgSetting.getInstantApp(userId)) {
+ // upgrade app from instant to full; we don't allow app downgrade
+ installed = true;
}
+ setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
}
if (installed) {
@@ -13338,6 +13343,29 @@
return PackageManager.INSTALL_SUCCEEDED;
}
+ void setInstantAppForUser(PackageSetting pkgSetting, int userId,
+ boolean instantApp, boolean fullApp) {
+ // no state specified; do nothing
+ if (!instantApp && !fullApp) {
+ return;
+ }
+ if (userId != UserHandle.USER_ALL) {
+ if (instantApp && !pkgSetting.getInstantApp(userId)) {
+ pkgSetting.setInstantApp(true /*instantApp*/, userId);
+ } else if (fullApp && pkgSetting.getInstantApp(userId)) {
+ pkgSetting.setInstantApp(false /*instantApp*/, userId);
+ }
+ } else {
+ for (int currentUserId : sUserManager.getUserIds()) {
+ if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
+ pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
+ } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
+ pkgSetting.setInstantApp(false /*instantApp*/, currentUserId);
+ }
+ }
+ }
+ }
+
boolean isUserRestricted(int userId, String restrictionKey) {
Bundle restrictions = sUserManager.getUserRestrictions(userId);
if (restrictions.getBoolean(restrictionKey, false)) {
@@ -13696,7 +13724,7 @@
return false;
}
// Ephemeral apps don't get the full verification treatment
- if ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "INSTALL_EPHEMERAL so skipping verification");
}
@@ -14488,7 +14516,7 @@
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
- final boolean ephemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
+ final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
@@ -14572,7 +14600,7 @@
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
- installFlags |= PackageManager.INSTALL_EPHEMERAL;
+ installFlags |= PackageManager.INSTALL_INSTANT_APP;
installFlags &= ~(PackageManager.INSTALL_EXTERNAL
|PackageManager.INSTALL_INTERNAL);
} else {
@@ -14906,7 +14934,7 @@
}
protected boolean isEphemeral() {
- return (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
+ return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
}
UserHandle getUser() {
@@ -14986,7 +15014,7 @@
}
try {
- final boolean isEphemeral = (installFlags & PackageManager.INSTALL_EPHEMERAL) != 0;
+ final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
@@ -15813,7 +15841,7 @@
private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
UserHandle user, String installerPackageName, PackageInstalledInfo res,
int installReason) {
- final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
+ final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
@@ -15837,17 +15865,17 @@
return;
}
+ final PackageSetting ps = mSettings.mPackages.get(pkgName);
+
// don't allow an upgrade from full to ephemeral
- final boolean oldIsEphemeral = oldPackage.applicationInfo.isInstantApp();
- if (isEphemeral && !oldIsEphemeral) {
- // can't downgrade from full to ephemeral
- Slog.w(TAG, "Can't replace app with ephemeral: " + pkgName);
- res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
+ if (isInstantApp && !ps.getInstantApp(user.getIdentifier())) {
+ // can't downgrade from full to instant
+ Slog.w(TAG, "Can't replace app with instant app: " + pkgName);
+ res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
return;
}
// verify signatures are valid
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
if (!checkUpgradeKeySetLP(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
@@ -16049,6 +16077,10 @@
childPs.oldCodePaths = ps.oldCodePaths;
}
}
+ // set instant app status, but, only if it's explicitly specified
+ final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+ final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
+ setInstantAppForUser(ps, user.getIdentifier(), instantApp, fullApp);
prepareAppDataAfterInstallLIF(newPackage);
addedPkg = true;
} catch (PackageManagerException e) {
@@ -16520,7 +16552,8 @@
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
|| (args.volumeUuid != null));
- final boolean ephemeral = ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0);
+ final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
+ final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
@@ -16531,6 +16564,12 @@
if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
scanFlags |= SCAN_DONT_KILL_APP;
}
+ if (instantApp) {
+ scanFlags |= SCAN_AS_INSTANT_APP;
+ }
+ if (fullApp) {
+ scanFlags |= SCAN_AS_FULL_APP;
+ }
// Result object to be returned
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -16538,10 +16577,10 @@
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Sanity check
- if (ephemeral && (forwardLocked || onExternal)) {
+ if (instantApp && (forwardLocked || onExternal)) {
Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
+ " external=" + onExternal);
- res.setReturnCode(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID);
+ res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
return;
}
@@ -16550,7 +16589,7 @@
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
- | (ephemeral ? PackageParser.PARSE_IS_EPHEMERAL : 0)
+ | (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
| (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
@@ -16569,7 +16608,7 @@
// // Ephemeral apps must have target SDK >= O.
// // TODO: Update conditional and error message when O gets locked down
-// if (ephemeral && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+// if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
// res.setError(PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID,
// "Ephemeral apps must have target SDK version of at least O");
// return;
@@ -16812,10 +16851,10 @@
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
return;
- } else if (ephemeral) {
- // Abort update; system app can't be replaced with an ephemeral app
- res.setError(INSTALL_FAILED_EPHEMERAL_INVALID,
- "Cannot update a system app with an ephemeral app");
+ } else if (instantApp) {
+ // Abort update; system app can't be replaced with an instant app
+ res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+ "Cannot update a system app with an instant app");
return;
}
}
@@ -17062,14 +17101,6 @@
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- private static boolean isEphemeral(PackageParser.Package pkg) {
- return pkg.applicationInfo.isInstantApp();
- }
-
- private static boolean isEphemeral(PackageSetting ps) {
- return ps.pkg != null && isEphemeral(ps.pkg);
- }
-
private static boolean isSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -17092,9 +17123,6 @@
private int packageFlagsToInstallFlags(PackageSetting ps) {
int installFlags = 0;
- if (isEphemeral(ps)) {
- installFlags |= PackageManager.INSTALL_EPHEMERAL;
- }
if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) {
// This existing package was an external ASEC install when we have
// the external flag without a UUID
@@ -17496,7 +17524,7 @@
try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
deleteFlags, "deletePackageX")) {
res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
- deleteFlags | REMOVE_CHATTY, info, true, null);
+ deleteFlags | FLAGS_REMOVE_CHATTY, info, true, null);
}
synchronized (mPackages) {
if (res) {
@@ -17646,7 +17674,7 @@
}
}
- removePackageLI(ps, (flags & REMOVE_CHATTY) != 0);
+ removePackageLI(ps, (flags & FLAGS_REMOVE_CHATTY) != 0);
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
final PackageParser.Package resolvedPkg;
@@ -18205,11 +18233,18 @@
Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId);
}
ps.setUserState(nextUserId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
- false /*installed*/, true /*stopped*/, true /*notLaunched*/,
- false /*hidden*/, false /*suspended*/, null, null, null,
+ false /*installed*/,
+ true /*stopped*/,
+ true /*notLaunched*/,
+ false /*hidden*/,
+ false /*suspended*/,
+ false /*instantApp*/,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
false /*blockUninstall*/,
- ps.readUserState(nextUserId).domainVerificationStatus, 0,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ ps.readUserState(nextUserId).domainVerificationStatus,
+ 0, PackageManager.INSTALL_REASON_UNKNOWN);
}
mSettings.writeKernelMappingLPr(ps);
}
@@ -21691,12 +21726,12 @@
final ApplicationInfo app = pkg.applicationInfo;
final int appId = UserHandle.getAppId(app.uid);
- Preconditions.checkNotNull(app.seinfo);
+ Preconditions.checkNotNull(app.seInfo);
long ceDataInode = -1;
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, app.seinfo, app.targetSdkVersion);
+ appId, app.seInfo, app.targetSdkVersion);
} catch (InstallerException e) {
if (app.isSystemApp()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
@@ -21704,7 +21739,7 @@
destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, app.seinfo, app.targetSdkVersion);
+ appId, app.seInfo, app.targetSdkVersion);
logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
} catch (InstallerException e2) {
logCriticalInfo(Log.DEBUG, "Recovery failed!");
@@ -22006,7 +22041,7 @@
installerPackageName = ps.installerPackageName;
packageAbiOverride = ps.cpuAbiOverrideString;
appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- seinfo = pkg.applicationInfo.seinfo;
+ seinfo = pkg.applicationInfo.seInfo;
label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
freezer = freezePackage(packageName, "movePackageInternal");
@@ -22815,8 +22850,8 @@
@Override
public boolean isPackageEphemeral(int userId, String packageName) {
synchronized (mPackages) {
- PackageParser.Package p = mPackages.get(packageName);
- return p != null ? p.applicationInfo.isInstantApp() : false;
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return ps != null ? ps.getInstantApp(userId) : false;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1203e4d..a7349fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -39,6 +39,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.VersionedPackage;
import android.content.res.AssetManager;
@@ -116,6 +117,8 @@
return runInstallRemove();
case "install-write":
return runInstallWrite();
+ case "install-existing":
+ return runInstallExisting();
case "compile":
return runCompile();
case "reconcile-secondary-dex-files":
@@ -301,6 +304,51 @@
return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
}
+ private int runInstallExisting() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_SYSTEM;
+ int installFlags = 0;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case "--ephemeral":
+ case "--instant":
+ installFlags |= PackageManager.INSTALL_INSTANT_APP;
+ installFlags &= ~PackageManager.INSTALL_FULL_APP;
+ break;
+ case "--full":
+ installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
+ installFlags |= PackageManager.INSTALL_FULL_APP;
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final String packageName = getNextArg();
+ if (packageName == null) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+
+ try {
+ final int res = mInterface.installExistingPackageAsUser(packageName, userId,
+ installFlags, PackageManager.INSTALL_REASON_UNKNOWN);
+ if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
+ throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+ }
+ pw.println("Package " + packageName + " installed for user: " + userId);
+ return 0;
+ } catch (RemoteException | NameNotFoundException e) {
+ pw.println(e.toString());
+ return 1;
+ }
+ }
+
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
@@ -1145,8 +1193,12 @@
sessionParams.abiOverride = checkAbiArgument(getNextArg());
break;
case "--ephemeral":
+ case "--instantapp":
sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
break;
+ case "--full":
+ sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
+ break;
case "--user":
params.userId = UserHandle.parseUserArg(getNextArgRequired());
break;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 0e11b0c..601377d6 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -397,11 +397,19 @@
modifyUserState(userId).blockUninstall = blockUninstall;
}
+ boolean getInstantApp(int userId) {
+ return readUserState(userId).instantApp;
+ }
+
+ void setInstantApp(boolean instantApp, int userId) {
+ modifyUserState(userId).instantApp = instantApp;
+ }
+
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
- boolean notLaunched, boolean hidden, boolean suspended,
+ boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
- ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
- int linkGeneration, int installReason) {
+ ArraySet<String> disabledComponents, boolean blockUninstall,
+ int domainVerifState, int linkGeneration, int installReason) {
PackageUserState state = modifyUserState(userId);
state.ceDataInode = ceDataInode;
state.enabled = enabled;
@@ -417,6 +425,7 @@
state.domainVerificationStatus = domainVerifState;
state.appLinkGeneration = linkGeneration;
state.installReason = installReason;
+ state.instantApp = instantApp;
}
ArraySet<String> getEnabledComponents(int userId) {
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 7e7de21..188e66f 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -17,6 +17,8 @@
package com.android.server.pm;
import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.SELinuxUtil;
import android.content.pm.Signature;
import android.os.Environment;
import android.util.Slog;
@@ -69,9 +71,6 @@
// Append v2 to existing seinfo label
private static final String SANDBOX_V2_STR = ":v2";
- // Append ephemeral to existing seinfo label
- private static final String EPHEMERAL_APP_STR = ":ephemeralapp";
-
// Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
@@ -279,31 +278,28 @@
*
* @param pkg object representing the package to be labeled.
*/
- public static void assignSeinfoValue(PackageParser.Package pkg) {
+ public static void assignSeInfoValue(PackageParser.Package pkg) {
synchronized (sPolicies) {
for (Policy policy : sPolicies) {
- String seinfo = policy.getMatchedSeinfo(pkg);
- if (seinfo != null) {
- pkg.applicationInfo.seinfo = seinfo;
+ String seInfo = policy.getMatchedSeInfo(pkg);
+ if (seInfo != null) {
+ pkg.applicationInfo.seInfo = seInfo;
break;
}
}
}
- if (pkg.applicationInfo.isInstantApp())
- pkg.applicationInfo.seinfo += EPHEMERAL_APP_STR;
-
if (pkg.applicationInfo.targetSandboxVersion == 2)
- pkg.applicationInfo.seinfo += SANDBOX_V2_STR;
+ pkg.applicationInfo.seInfo += SANDBOX_V2_STR;
if (pkg.applicationInfo.isPrivilegedApp())
- pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
+ pkg.applicationInfo.seInfo += PRIVILEGED_APP_STR;
- pkg.applicationInfo.seinfo += TARGETSDKVERSION_STR + pkg.applicationInfo.targetSdkVersion;
+ pkg.applicationInfo.seInfo += TARGETSDKVERSION_STR + pkg.applicationInfo.targetSdkVersion;
if (DEBUG_POLICY_INSTALL) {
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + pkg.applicationInfo.seinfo);
+ "seinfo=" + pkg.applicationInfo.seInfo);
}
}
}
@@ -438,7 +434,7 @@
* @return A string representing the seinfo matched during policy lookup.
* A value of null can also be returned if no match occured.
*/
- public String getMatchedSeinfo(PackageParser.Package pkg) {
+ public String getMatchedSeInfo(PackageParser.Package pkg) {
// Check for exact signature matches across all certs.
Signature[] certs = mCerts.toArray(new Signature[0]);
if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6156802..a8a5ff0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -219,6 +219,7 @@
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
private static final String ATTR_INSTALL_REASON = "install-reason";
+ private static final String ATTR_INSTANT_APP = "instant-app";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_FINGERPRINT = "fingerprint";
@@ -687,7 +688,7 @@
PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
- UserHandle installUser, boolean allowInstall, String parentPkgName,
+ UserHandle installUser, boolean allowInstall, boolean instantApp, String parentPkgName,
List<String> childPkgNames, UserManagerService userManager,
String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
final PackageSetting pkgSetting;
@@ -745,14 +746,17 @@
|| installUserId == user.id;
pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
installed,
- true, // stopped,
- true, // notLaunched
- false, // hidden
- false, // suspended
- null, null, null,
- false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ true /*stopped*/,
+ true /*notLaunched*/,
+ false /*hidden*/,
+ false /*suspended*/,
+ instantApp,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
+ false /*blockUninstall*/,
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
+ 0, PackageManager.INSTALL_REASON_UNKNOWN);
}
}
}
@@ -1643,15 +1647,18 @@
// consider all applications to be installed.
for (PackageSetting pkg : mPackages.values()) {
pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
- true, // installed
- false, // stopped
- false, // notLaunched
- false, // hidden
- false, // suspended
- null, null, null,
- false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ true /*installed*/,
+ false /*stopped*/,
+ false /*notLaunched*/,
+ false /*hidden*/,
+ false /*suspended*/,
+ false /*instantApp*/,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
+ false /*blockUninstall*/,
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
+ 0, PackageManager.INSTALL_REASON_UNKNOWN);
}
return;
}
@@ -1718,6 +1725,8 @@
false);
final boolean blockUninstall = XmlUtils.readBooleanAttribute(parser,
ATTR_BLOCK_UNINSTALL, false);
+ final boolean instantApp = XmlUtils.readBooleanAttribute(parser,
+ ATTR_INSTANT_APP, false);
final int enabled = XmlUtils.readIntAttribute(parser, ATTR_ENABLED,
COMPONENT_ENABLED_STATE_DEFAULT);
final String enabledCaller = parser.getAttributeValue(null,
@@ -1754,8 +1763,9 @@
}
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
- hidden, suspended, enabledCaller, enabledComponents, disabledComponents,
- blockUninstall, verifState, linkGeneration, installReason);
+ hidden, suspended, instantApp, enabledCaller, enabledComponents,
+ disabledComponents, blockUninstall, verifState, linkGeneration,
+ installReason);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -2025,6 +2035,9 @@
if (ustate.blockUninstall) {
serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
}
+ if (ustate.instantApp) {
+ serializer.attribute(null, ATTR_INSTANT_APP, "true");
+ }
if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
serializer.attribute(null, ATTR_ENABLED,
Integer.toString(ustate.enabled));
@@ -2682,7 +2695,7 @@
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append(" ");
- sb.append(ai.seinfo);
+ sb.append(ai.seInfo);
sb.append(" ");
if (gids != null && gids.length > 0) {
sb.append(gids[0]);
@@ -4140,7 +4153,7 @@
volumeUuids[i] = ps.volumeUuid;
names[i] = ps.name;
appIds[i] = ps.appId;
- seinfos[i] = ps.pkg.applicationInfo.seinfo;
+ seinfos[i] = ps.pkg.applicationInfo.seInfo;
targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
}
}
@@ -4429,7 +4442,7 @@
ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE, "DIRECT_BOOT_AWARE",
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, "PARTIALLY_DIRECT_BOOT_AWARE",
- ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
+ ApplicationInfo.PRIVATE_FLAG_INSTANT, "EPHEMERAL",
ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET, "RESIZEABLE_ACTIVITIES_EXPLICITLY_SET",
ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION, "RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION",
@@ -4502,6 +4515,7 @@
pw.print(ps.getSuspended(user.id) ? "SU" : "su");
pw.print(ps.getStopped(user.id) ? "S" : "s");
pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
+ pw.print(ps.getInstantApp(user.id) ? "IA" : "ia");
pw.print(",");
pw.print(ps.getEnabled(user.id));
String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
@@ -4755,6 +4769,8 @@
pw.print(ps.getNotLaunched(user.id));
pw.print(" enabled=");
pw.println(ps.getEnabled(user.id));
+ pw.print(" instant=");
+ pw.println(ps.getInstantApp(user.id));
String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
if (lastDisabledAppCaller != null) {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2b2bb48..ba8f7e9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7863,7 +7863,7 @@
// Install the profile owner if not present.
if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle,
- PackageManager.INSTALL_REASON_POLICY);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls for createAndManageUser, "
@@ -8182,7 +8182,7 @@
// Install the app.
mIPackageManager.installExistingPackageAsUser(packageName, userId,
- PackageManager.INSTALL_REASON_POLICY);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
} catch (RemoteException re) {
// shouldn't happen
@@ -8224,7 +8224,7 @@
if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
numberOfAppsInstalled++;
mIPackageManager.installExistingPackageAsUser(packageName, userId,
- PackageManager.INSTALL_REASON_POLICY);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
} else {
Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ " system app");
diff --git a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
index 3fa72dc..90c58d0 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
@@ -104,7 +104,7 @@
}
try {
mPackageManager.installExistingPackageAsUser(packageName, userId,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} finally {
@@ -175,4 +175,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index db010b8..88f1a53 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -280,6 +280,21 @@
@Test
@UiThreadTest
+ public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
+ mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+ generateNotificationRecord(null).getNotification(), new int[1], 0);
+ waitForIdle();
+ mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+ generateNotificationRecord(null).getNotification(), new int[1], 0);
+ mBinderService.cancelNotificationWithTag(mContext.getPackageName(), "tag", 0, 0);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(mContext.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ @UiThreadTest
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index e2e1844..100338e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1053,7 +1053,7 @@
ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
if (mEphemeralPackages.contains(PackageWithUser.of(userId, packageName))) {
- ret.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
+ ret.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
}
if (mSystemPackages.contains(packageName)) {
ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index baf60c5..325d99a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -388,6 +388,7 @@
ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
null /*installUser*/,
false /*allowInstall*/,
+ false /*instantApp*/,
null /*parentPkgName*/,
null /*childPkgNames*/,
UserManagerService.getInstance(),
@@ -428,6 +429,7 @@
0 /*pkgPrivateFlags*/,
UserHandle.SYSTEM /*installUser*/,
true /*allowInstall*/,
+ false /*instantApp*/,
null /*parentPkgName*/,
null /*childPkgNames*/,
UserManagerService.getInstance(),
@@ -471,6 +473,7 @@
0 /*pkgPrivateFlags*/,
null /*installUser*/,
false /*allowInstall*/,
+ false /*instantApp*/,
null /*parentPkgName*/,
null /*childPkgNames*/,
UserManagerService.getInstance(),
@@ -514,6 +517,7 @@
0 /*pkgPrivateFlags*/,
null /*installUser*/,
false /*allowInstall*/,
+ false /*instantApp*/,
null /*parentPkgName*/,
null /*childPkgNames*/,
UserManagerService.getInstance(),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e5640c7..5591029 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -380,7 +380,7 @@
assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs));
assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs));
assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs));
- assertEquals(a.seinfo, that.seinfo);
+ assertEquals(a.seInfo, that.seInfo);
assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
assertEquals(a.dataDir, that.dataDir);
assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
index 346dc42..a8c39c4 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
@@ -104,7 +104,7 @@
null, null);
// Verify that we try to install the package in system user.
verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN);
}
assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
"1",
@@ -141,7 +141,7 @@
null, null);
// Verify that we try to install the package in system user.
verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN);
}
assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
"1",