Merge changes I8f5a756a,I2bac468f,I043dfefa,I2c55f96e into oc-dev
* changes:
Bluetooth: expand comments on new PHY constants
Bluetooth: document status value in PHY read/update
Bluetooth: Add handler parameter to connectGatt
Get rid of the IAdvertiserCallabck
diff --git a/Android.mk b/Android.mk
index 6134fe2..e58f306 100644
--- a/Android.mk
+++ b/Android.mk
@@ -921,6 +921,7 @@
# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
# not be referenced in the documentation.
framework_docs_LOCAL_DROIDDOC_OPTIONS := \
+ -android \
-knowntags ./frameworks/base/docs/knowntags.txt \
-knowntags ./libcore/known_oj_tags.txt \
-hidePackage com.android.org.conscrypt \
@@ -950,8 +951,8 @@
-since $(SRC_API_DIR)/24.txt 24 \
-since $(SRC_API_DIR)/25.txt 25 \
-since ./frameworks/base/api/current.txt O \
- -werror -hide 111 -hide 113 \
- -overview $(LOCAL_PATH)/core/java/overview.html
+ -werror -hide 111 -hide 113 -hide 121 \
+ -overview $(LOCAL_PATH)/core/java/overview.html \
# Allow the support library to add its own droiddoc options.
include $(LOCAL_PATH)/../support/droiddoc.mk
diff --git a/api/current.txt b/api/current.txt
index c05672f..bd3d07a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8938,7 +8938,7 @@
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
- field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companiondevice";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -24779,7 +24779,6 @@
}
public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
- ctor public TvContract.WatchNextPrograms();
field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
diff --git a/api/removed.txt b/api/removed.txt
index 73dd096..c132385 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -350,10 +350,6 @@
field public static final deprecated java.lang.String TIMESTAMP = "timestamp";
}
- public static final class FontsContract.Columns implements android.provider.BaseColumns {
- field public static final java.lang.String STYLE = "font_style";
- }
-
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 719d206..bcbd248 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9443,7 +9443,7 @@
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
- field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companiondevice";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
@@ -26777,7 +26777,6 @@
}
public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
- ctor public TvContract.WatchNextPrograms();
field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
diff --git a/api/system-removed.txt b/api/system-removed.txt
index ed81363..039cd74 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -344,10 +344,6 @@
field public static final deprecated java.lang.String TIMESTAMP = "timestamp";
}
- public static final class FontsContract.Columns implements android.provider.BaseColumns {
- field public static final java.lang.String STYLE = "font_style";
- }
-
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index e59ca81..3ee9cb6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8971,7 +8971,7 @@
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
- field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companion_device";
+ field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companiondevice";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -24887,7 +24887,6 @@
}
public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BaseTvColumns {
- ctor public TvContract.WatchNextPrograms();
field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 73dd096..c132385 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -350,10 +350,6 @@
field public static final deprecated java.lang.String TIMESTAMP = "timestamp";
}
- public static final class FontsContract.Columns implements android.provider.BaseColumns {
- field public static final java.lang.String STYLE = "font_style";
- }
-
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 46ce94f..195ba24 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -51,7 +51,6 @@
import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -90,6 +89,7 @@
import android.provider.CallLog;
import android.provider.ContactsContract;
import android.provider.Downloads;
+import android.provider.FontsContract;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
import android.security.net.config.NetworkSecurityConfigProvider;
@@ -5793,7 +5793,7 @@
}
// Preload fonts resources
- Typeface.setApplicationContext(appContext);
+ FontsContract.setApplicationContextForResources(appContext);
try {
final ApplicationInfo info =
getPackageManager().getApplicationInfo(
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 0676bca..6d87de8 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -20,7 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RawRes;
+import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -103,6 +105,7 @@
* <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
* Activities that support this intent should specify a MIME filter of "image/*"
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CROP_AND_SET_WALLPAPER =
"android.service.wallpaper.CROP_AND_SET_WALLPAPER";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a939eb0..7855b92 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1518,7 +1518,8 @@
* Service action: Action for a service that device owner and profile owner can optionally
* own. If a device owner or a profile owner has such a service, the system tries to keep
* a bound connection to it, in order to keep their process always running.
- * The service must not be exported.
+ * The service must be protected with the {@link android.Manifest.permission#BIND_DEVICE_ADMIN}
+ * permission.
*/
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String ACTION_DEVICE_ADMIN_SERVICE
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 42ef871..d0ce3cf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3769,7 +3769,7 @@
* @see #getSystemService
* @see android.companion.CompanionDeviceManager
*/
- public static final String COMPANION_DEVICE_SERVICE = "companion_device";
+ public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
/**
* Use with {@link #getSystemService} to retrieve a
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9c87ff2..da43fec 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1399,6 +1399,7 @@
* <p>Input: nothing
* <p>Output: nothing
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
/**
@@ -2061,6 +2062,7 @@
* temporary system dialog to dismiss. Some examples of temporary system
* dialogs are the notification window-shade and the recent tasks dialog.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
/**
* Broadcast Action: Trigger the download and eventual installation
@@ -2590,6 +2592,7 @@
* @deprecated replaced by android.os.storage.StorageEventListener
*/
@Deprecated
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
/**
@@ -2600,6 +2603,7 @@
* @deprecated replaced by android.os.storage.StorageEventListener
*/
@Deprecated
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
/**
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index d64f018..c9bce53 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
@@ -33,6 +34,8 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
@@ -283,9 +286,22 @@
private static final int STATE_VERIFIED = 0x00001000;
private int mVerifyState;
-
+ /** @hide */
+ public static final int VISIBILITY_NONE = 0;
+ /** @hide */
+ public static final int VISIBILITY_EXPLICIT = 1;
+ /** @hide */
+ public static final int VISIBILITY_IMPLICIT = 2;
+ /** @hide */
+ @IntDef(prefix = { "VISIBILITY_" }, value = {
+ VISIBILITY_NONE,
+ VISIBILITY_EXPLICIT,
+ VISIBILITY_IMPLICIT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InstantAppVisibility {}
/** Whether or not the intent filter is visible to instant apps. */
- private boolean mVisibleToInstantApp;
+ private @InstantAppVisibility int mInstantAppVisibility;
// These functions are the start of more optimized code for managing
// the string sets... not yet implemented.
@@ -452,7 +468,7 @@
}
mHasPartialTypes = o.mHasPartialTypes;
mVerifyState = o.mVerifyState;
- mVisibleToInstantApp = o.mVisibleToInstantApp;
+ mInstantAppVisibility = o.mInstantAppVisibility;
}
/**
@@ -655,12 +671,24 @@
}
/** @hide */
- public void setVisibleToInstantApp(boolean visibleToInstantApp) {
- mVisibleToInstantApp = visibleToInstantApp;
+ public void setVisibilityToInstantApp(@InstantAppVisibility int visibility) {
+ mInstantAppVisibility = visibility;
+ }
+ /** @hide */
+ public @InstantAppVisibility int getVisibilityToInstantApp() {
+ return mInstantAppVisibility;
}
/** @hide */
public boolean isVisibleToInstantApp() {
- return mVisibleToInstantApp;
+ return mInstantAppVisibility != VISIBILITY_NONE;
+ }
+ /** @hide */
+ public boolean isExplicitlyVisibleToInstantApp() {
+ return mInstantAppVisibility == VISIBILITY_EXPLICIT;
+ }
+ /** @hide */
+ public boolean isImplicitlyVisibleToInstantApp() {
+ return mInstantAppVisibility == VISIBILITY_IMPLICIT;
}
/**
@@ -1859,7 +1887,7 @@
dest.writeInt(mPriority);
dest.writeInt(mHasPartialTypes ? 1 : 0);
dest.writeInt(getAutoVerify() ? 1 : 0);
- dest.writeInt(isVisibleToInstantApp() ? 1 : 0);
+ dest.writeInt(mInstantAppVisibility);
}
/**
@@ -1928,7 +1956,7 @@
mPriority = source.readInt();
mHasPartialTypes = source.readInt() > 0;
setAutoVerify(source.readInt() > 0);
- setVisibleToInstantApp(source.readInt() > 0);
+ setVisibilityToInstantApp(source.readInt());
}
private final boolean findMimeType(String type) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b01e6a1..0be0885 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.IntDef;
+import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Configuration.NativeConfig;
import android.os.Parcel;
@@ -412,17 +413,33 @@
public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
/**
- * Bit in {@link #flags} indicating if the activity is visible to ephemeral applications.
+ * Bit in {@link #flags} indicating if the activity is visible to instant
+ * applications. The activity is visible if it's either implicitly or
+ * explicitly exposed.
* @hide
*/
- public static final int FLAG_VISIBLE_TO_EPHEMERAL = 0x100000;
+ public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is implicitly visible
+ * to instant applications. Implicitly visible activities are those that
+ * implement certain intent-filters:
+ * <ul>
+ * <li>action {@link Intent#CATEGORY_BROWSABLE}</li>
+ * <li>action {@link Intent#ACTION_SEND}</li>
+ * <li>action {@link Intent#ACTION_SENDTO}</li>
+ * <li>action {@link Intent#ACTION_SEND_MULTIPLE}</li>
+ * </ul>
+ * @hide
+ */
+ public static final int FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP = 0x200000;
/**
* Bit in {@link #flags} indicating if the activity supports picture-in-picture mode.
* See {@link android.R.attr#supportsPictureInPicture}.
* @hide
*/
- public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x200000;
+ public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x400000;
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ecaf7eb..d2468d9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -461,12 +461,20 @@
/**
* Internal {@link PackageInfo} flag: include only components that are exposed to
- * ephemeral apps.
+ * instant apps. Matched components may have been either explicitly or implicitly
+ * exposed.
* @hide
*/
public static final int MATCH_VISIBLE_TO_INSTANT_APP_ONLY = 0x01000000;
/**
+ * Internal {@link PackageInfo} flag: include only components that have been
+ * explicitly exposed to instant apps.
+ * @hide
+ */
+ public static final int MATCH_EXPLICITLY_VISIBLE_ONLY = 0x02000000;
+
+ /**
* Internal flag used to indicate that a system component has done their
* homework and verified that they correctly handle packages and components
* that come and go over time. In particular:
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8609351..e4db0f0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4271,7 +4271,7 @@
boolean visibleToEphemeral =
sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
if (visibleToEphemeral) {
- a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
}
@@ -4313,9 +4313,17 @@
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
- intent.setVisibleToInstantApp(visibleToEphemeral || isImplicitlyExposedIntent(intent));
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : !receiver && isImplicitlyExposedIntent(intent)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intent.setVisibilityToInstantApp(visibility);
if (intent.isVisibleToInstantApp()) {
- a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intent.isImplicitlyVisibleToInstantApp()) {
+ a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
if (LOG_UNSAFE_BROADCASTS && receiver
&& (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
@@ -4346,9 +4354,17 @@
owner.preferredActivityFilters.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
- intent.setVisibleToInstantApp(visibleToEphemeral || isImplicitlyExposedIntent(intent));
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : !receiver && isImplicitlyExposedIntent(intent)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intent.setVisibilityToInstantApp(visibility);
if (intent.isVisibleToInstantApp()) {
- a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intent.isImplicitlyVisibleToInstantApp()) {
+ a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
} else if (parser.getName().equals("meta-data")) {
if ((a.metaData = parseMetaData(res, parser, a.metaData,
@@ -4358,16 +4374,18 @@
// we don't have an attribute [or it's false], but, we have meta-data
if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
visibleToEphemeral = true; // set in case there are more intent filters
- a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
// cycle through any filters already seen
for (int i = a.intents.size() - 1; i >= 0; --i) {
- a.intents.get(i).setVisibleToInstantApp(true /*visibleToInstantApp*/);
+ a.intents.get(i)
+ .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
}
if (owner.preferredActivityFilters != null) {
for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) {
owner.preferredActivityFilters.get(i)
- .setVisibleToInstantApp(true /*visibleToInstantApp*/);
+ .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
}
}
}
@@ -4645,7 +4663,7 @@
// TODO add visibleToInstantApps attribute to activity alias
final boolean visibleToEphemeral =
- ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
+ ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
sa.recycle();
@@ -4673,13 +4691,20 @@
+ mArchiveSourcePath + " "
+ parser.getPositionDescription());
} else {
- intent.setVisibleToInstantApp(
- visibleToEphemeral || isImplicitlyExposedIntent(intent));
a.intents.add(intent);
}
// adjust activity flags when we implicitly expose it via a browsable filter
+ final int visibility = visibleToEphemeral
+ ? IntentFilter.VISIBILITY_EXPLICIT
+ : isImplicitlyExposedIntent(intent)
+ ? IntentFilter.VISIBILITY_IMPLICIT
+ : IntentFilter.VISIBILITY_NONE;
+ intent.setVisibilityToInstantApp(visibility);
if (intent.isVisibleToInstantApp()) {
- a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+ }
+ if (intent.isImplicitlyVisibleToInstantApp()) {
+ a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
} else if (parser.getName().equals("meta-data")) {
if ((a.metaData=parseMetaData(res, parser, a.metaData,
@@ -4822,7 +4847,7 @@
final boolean visibleToEphemeral =
sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
if (visibleToEphemeral) {
- p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
}
@@ -4874,12 +4899,11 @@
intent, outError)) {
return false;
}
- outInfo.intents.add(intent);
- // adjust provider flags when we implicitly expose it via a browsable filter
- intent.setVisibleToInstantApp(visibleToEphemeral || isImplicitlyExposedIntent(intent));
- if (intent.isVisibleToInstantApp()) {
- outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ if (visibleToEphemeral) {
+ intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+ outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
+ outInfo.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
if ((outInfo.metaData=parseMetaData(res, parser,
@@ -4889,11 +4913,12 @@
// we don't have an attribute [or it's false], but, we have meta-data
if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
visibleToEphemeral = true; // set in case there are more intent filters
- outInfo.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
// cycle through any filters already seen
for (int i = outInfo.intents.size() - 1; i >= 0; --i) {
- outInfo.intents.get(i).setVisibleToInstantApp(true /*visibleToInstantApp*/);
+ outInfo.intents.get(i)
+ .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
}
}
@@ -5149,7 +5174,7 @@
boolean visibleToEphemeral =
sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
- s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
}
@@ -5180,10 +5205,9 @@
intent, outError)) {
return null;
}
- // adjust activity flags when we implicitly expose it via a browsable filter
- intent.setVisibleToInstantApp(visibleToEphemeral || isImplicitlyExposedIntent(intent));
- if (intent.isVisibleToInstantApp()) {
- s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ if (visibleToEphemeral) {
+ intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+ s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
}
s.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
@@ -5194,11 +5218,12 @@
// we don't have an attribute [or it's false], but, we have meta-data
if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
visibleToEphemeral = true; // set in case there are more intent filters
- s.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
+ s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
owner.visibleToInstantApps = true;
// cycle through any filters already seen
for (int i = s.intents.size() - 1; i >= 0; --i) {
- s.intents.get(i).setVisibleToInstantApp(true /*visibleToInstantApp*/);
+ s.intents.get(i)
+ .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
}
}
} else {
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 8c21563..91dc06e 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -79,7 +79,7 @@
* Bit in {@link #flags} indicating if the provider is visible to ephemeral applications.
* @hide
*/
- public static final int FLAG_VISIBLE_TO_EPHEMERAL = 0x100000;
+ public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000;
/**
* Bit in {@link #flags}: If set, a single instance of the provider will
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index f0766be..c683ea5 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -59,7 +59,7 @@
* Bit in {@link #flags} indicating if the service is visible to ephemeral applications.
* @hide
*/
- public static final int FLAG_VISIBLE_TO_EPHEMERAL = 0x100000;
+ public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000;
/**
* Bit in {@link #flags}: If set, a single instance of the service will
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index f5ad5cc..51506b0 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -285,17 +285,22 @@
}
// Initialize a client for data_injection.
if (sInjectEventQueue == null) {
- sInjectEventQueue = new InjectEventQueue(mMainLooper, this,
- mContext.getPackageName());
+ try {
+ sInjectEventQueue = new InjectEventQueue(
+ mMainLooper, this, mContext.getPackageName());
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Cannot create InjectEventQueue: " + e);
+ }
}
+ return sInjectEventQueue != null;
} else {
// If data injection is being disabled clean up the native resources.
if (sInjectEventQueue != null) {
sInjectEventQueue.dispose();
sInjectEventQueue = null;
}
+ return true;
}
- return true;
}
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 7bfb5d0..211d54d 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -135,7 +135,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(
+ @IntDef(prefix = {"TEMPLATE_"}, value =
{TEMPLATE_PREVIEW,
TEMPLATE_STILL_CAPTURE,
TEMPLATE_RECORD,
@@ -757,7 +757,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(
+ @IntDef(prefix = {"SESSION_OPERATION_MODE"}, value =
{SESSION_OPERATION_MODE_NORMAL,
SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED,
SESSION_OPERATION_MODE_VENDOR_START})
@@ -808,10 +808,9 @@
* create a builder specific for that device and template and override the
* settings as desired, instead.</p>
*
- * @param templateType An enumeration selecting the use case for this
- * request; one of the CameraDevice.TEMPLATE_ values. Not all template
- * types are supported on every device. See the documentation for each
- * template type for details.
+ * @param templateType An enumeration selecting the use case for this request. Not all template
+ * types are supported on every device. See the documentation for each template type for
+ * details.
* @return a builder for a capture request, initialized with default
* settings for that template, and no output streams
*
@@ -969,7 +968,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(
+ @IntDef(prefix = {"ERROR_"}, value =
{ERROR_CAMERA_IN_USE,
ERROR_MAX_CAMERAS_IN_USE,
ERROR_CAMERA_DISABLED,
@@ -1052,8 +1051,7 @@
* this happens. Further attempts at recovery are error-code specific.</p>
*
* @param camera The device reporting the error
- * @param error The error code, one of the
- * {@code StateCallback.ERROR_*} values.
+ * @param error The error code.
*
* @see #ERROR_CAMERA_IN_USE
* @see #ERROR_MAX_CAMERAS_IN_USE
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index 8bb33f1..fbe0839 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -51,7 +51,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(
+ @IntDef(prefix = {"REASON_"}, value =
{REASON_ERROR,
REASON_FLUSHED })
public @interface FailureReason {};
@@ -119,7 +119,7 @@
* Determine why the request was dropped, whether due to an error or to a user
* action.
*
- * @return int One of {@code REASON_*} integer constants.
+ * @return int The reason code.
*
* @see #REASON_ERROR
* @see #REASON_FLUSHED
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index ae92457..b2a2aaf 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,9 +17,9 @@
package android.hardware.usb;
-import com.android.internal.util.Preconditions;
-
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -30,6 +30,8 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.HashMap;
/**
@@ -109,6 +111,7 @@
* for the attached device
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_DEVICE_ATTACHED =
"android.hardware.usb.action.USB_DEVICE_ATTACHED";
@@ -121,6 +124,7 @@
* for the detached device
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_DEVICE_DETACHED =
"android.hardware.usb.action.USB_DEVICE_DETACHED";
@@ -133,6 +137,7 @@
* for the attached accessory
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_ACCESSORY_ATTACHED =
"android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
@@ -145,6 +150,7 @@
* for the attached accessory that was detached
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_ACCESSORY_DETACHED =
"android.hardware.usb.action.USB_ACCESSORY_DETACHED";
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index cb85eef..db84b6f 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.util.Log;
@@ -67,6 +69,7 @@
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DROPBOX_ENTRY_ADDED =
"android.intent.action.DROPBOX_ENTRY_ADDED";
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index b31b295..42d5ce1 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -18,6 +18,8 @@
import com.android.internal.R;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -2164,6 +2166,7 @@
* @deprecated Do not use. This is not supported.
*/
@Deprecated
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String FILTER_CONTACTS_ACTION =
"com.android.contacts.action.FILTER_CONTACTS";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b4f19d8..5408e13 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -17,6 +17,8 @@
package android.provider;
import android.accounts.Account;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -8401,6 +8403,7 @@
* Action used to launch the system contacts application and bring up a QuickContact dialog
* for the provided {@link Contacts} entry.
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_QUICK_CONTACT =
"android.provider.action.QUICK_CONTACT";
@@ -8924,6 +8927,7 @@
* @see #METADATA_ACCOUNT_TYPE
* @see #METADATA_MIMETYPE
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS =
"android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index e68c7bb..bcd1b6b 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -105,14 +105,6 @@
*/
public static final String VARIATION_SETTINGS = "font_variation_settings";
/**
- * DO NOT USE THIS COLUMN.
- * This column is kept for preventing demo apps.
- * TODO: Remove once nobody uses this column.
- * @hide
- * @removed
- */
- public static final String STYLE = "font_style";
- /**
* Constant used to request data from a font provider. The cursor returned from the query
* should have this column populated with the int weight for the resulting font. This value
* should be between 100 and 900. The most common values are 400 for regular weight and 700
@@ -159,38 +151,24 @@
public static final int RESULT_CODE_MALFORMED_QUERY = 3;
}
- /**
- * Constant used to identify the List of {@link ParcelFileDescriptor} item in the Bundle
- * returned to the ResultReceiver in getFont.
- * @hide
- */
- public static final String PARCEL_FONT_RESULTS = "font_results";
- // Error codes internal to the system, which can not come from a provider. To keep the number
- // space open for new provider codes, these should all be negative numbers.
- /** @hide */
- public static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
- /** @hide */
- public static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
- // Note -3 is used by Typeface to indicate the font failed to load.
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static Handler sHandler;
+ @GuardedBy("sLock")
+ private static HandlerThread sThread;
+ @GuardedBy("sLock")
+ private static Set<String> sInQueueSet;
- private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
-
- private final Context mContext;
- private final PackageManager mPackageManager;
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private Handler mHandler;
- @GuardedBy("mLock")
- private HandlerThread mThread;
- @GuardedBy("mLock")
- private Set<String> mInQueueSet;
+ private volatile static Context sContext; // set once in setApplicationContextForResources
private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
+ private FontsContract() {
+ }
+
/** @hide */
- public FontsContract(Context context) {
- mContext = context.getApplicationContext();
- mPackageManager = mContext.getPackageManager();
+ public static void setApplicationContextForResources(Context context) {
+ sContext = context.getApplicationContext();
}
/**
@@ -323,24 +301,27 @@
}
}
+ private static final int THREAD_RENEWAL_THRESHOLD_MS = 10000;
+
// We use a background thread to post the content resolving work for all requests on. This
// thread should be quit/stopped after all requests are done.
- private final Runnable mReplaceDispatcherThreadRunnable = new Runnable() {
+ // TODO: Factor out to other class. Consider to switch MessageQueue.IdleHandler.
+ private static final Runnable sReplaceDispatcherThreadRunnable = new Runnable() {
@Override
public void run() {
- synchronized (mLock) {
- if (mThread != null) {
- mThread.quitSafely();
- mThread = null;
- mHandler = null;
- mInQueueSet = null;
+ synchronized (sLock) {
+ if (sThread != null) {
+ sThread.quitSafely();
+ sThread = null;
+ sHandler = null;
+ sInQueueSet = null;
}
}
}
};
/** @hide */
- public Typeface getFontOrWarmUpCache(FontRequest request) {
+ public static Typeface getFontOrWarmUpCache(FontRequest request) {
final String id = request.getIdentifier();
Typeface cachedTypeface = sTypefaceCache.get(id);
if (cachedTypeface != null) {
@@ -350,25 +331,25 @@
// Unfortunately the typeface is not available at this time, but requesting from the font
// provider takes too much time. For now, request the font data to ensure it is in the cache
// next time and return.
- synchronized (mLock) {
- if (mHandler == null) {
- mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
- mThread.start();
- mHandler = new Handler(mThread.getLooper());
- mInQueueSet = new ArraySet<String>();
+ synchronized (sLock) {
+ if (sHandler == null) {
+ sThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
+ sThread.start();
+ sHandler = new Handler(sThread.getLooper());
+ sInQueueSet = new ArraySet<>();
}
- if (mInQueueSet.contains(id)) {
+ if (sInQueueSet.contains(id)) {
return null; // Already requested.
}
- mInQueueSet.add(id);
- mHandler.post(() -> {
- synchronized (mLock) {
- mInQueueSet.remove(id);
+ sInQueueSet.add(id);
+ sHandler.post(() -> {
+ synchronized (sLock) {
+ sInQueueSet.remove(id);
}
try {
- FontFamilyResult result = fetchFonts(mContext, null, request);
+ FontFamilyResult result = fetchFonts(sContext, null, request);
if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
- Typeface typeface = buildTypeface(mContext, null, result.getFonts());
+ Typeface typeface = buildTypeface(sContext, null, result.getFonts());
if (typeface != null) {
sTypefaceCache.put(id, typeface);
}
@@ -377,8 +358,8 @@
// Ignore.
}
});
- mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
- mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
+ sHandler.removeCallbacks(sReplaceDispatcherThreadRunnable);
+ sHandler.postDelayed(sReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
}
return null;
}
@@ -391,12 +372,12 @@
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
* provider was not found on the device.
*/
- public static final int FAIL_REASON_PROVIDER_NOT_FOUND = RESULT_CODE_PROVIDER_NOT_FOUND;
+ public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
* provider must be authenticated and the given certificates do not match its signature.
*/
- public static final int FAIL_REASON_WRONG_CERTIFICATES = RESULT_CODE_WRONG_CERTIFICATES;
+ public static final int FAIL_REASON_WRONG_CERTIFICATES = -2;
/**
* Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
* returned by the provider was not loaded properly.
@@ -767,7 +748,7 @@
.build();
try (Cursor cursor = context.getContentResolver().query(uri, new String[] { Columns._ID,
Columns.FILE_ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS,
- Columns.STYLE, Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
+ Columns.WEIGHT, Columns.ITALIC, Columns.RESULT_CODE },
"query = ?", new String[] { request.getQuery() }, null, cancellationSignal);) {
// TODO: Should we restrict the amount of fonts that can be returned?
// TODO: Write documentation explaining that all results should be from the same family.
@@ -780,7 +761,6 @@
final int vsColumnIndex = cursor.getColumnIndex(Columns.VARIATION_SETTINGS);
final int weightColumnIndex = cursor.getColumnIndex(Columns.WEIGHT);
final int italicColumnIndex = cursor.getColumnIndex(Columns.ITALIC);
- final int styleColumnIndex = cursor.getColumnIndex(Columns.STYLE);
while (cursor.moveToNext()) {
int resultCode = resultCodeColumnIndex != -1
? cursor.getInt(resultCodeColumnIndex) : Columns.RESULT_CODE_OK;
@@ -797,17 +777,11 @@
long id = cursor.getLong(fileIdColumnIndex);
fileUri = ContentUris.withAppendedId(fileBaseUri, id);
}
- // TODO: Stop using STYLE column and enforce WEIGHT/ITALIC column.
int weight;
boolean italic;
if (weightColumnIndex != -1 && italicColumnIndex != -1) {
weight = cursor.getInt(weightColumnIndex);
italic = cursor.getInt(italicColumnIndex) == 1;
- } else if (styleColumnIndex != -1) {
- final int style = cursor.getInt(styleColumnIndex);
- weight = (style & Typeface.BOLD) != 0 ?
- Typeface.Builder.BOLD_WEIGHT : Typeface.Builder.NORMAL_WEIGHT;
- italic = (style & Typeface.ITALIC) != 0;
} else {
weight = Typeface.Builder.NORMAL_WEIGHT;
italic = false;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 93adf83..13e1e26 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1498,6 +1498,7 @@
* May also contain the extra EXTRA_MAX_BYTES.
* @see #EXTRA_MAX_BYTES
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String RECORD_SOUND_ACTION =
"android.provider.MediaStore.RECORD_SOUND";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 69371be..cbd41c3 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6943,6 +6943,7 @@
ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ AUTOFILL_SERVICE,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_NOTIFICATION_LISTENERS,
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
index d94af8a..68d0309 100644
--- a/core/java/android/util/MergedConfiguration.java
+++ b/core/java/android/util/MergedConfiguration.java
@@ -21,6 +21,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.io.PrintWriter;
+
/**
* Container that holds global and override config and their merge product.
* Merged configuration updates automatically whenever global or override configs are updated via
@@ -41,6 +43,10 @@
setConfiguration(globalConfig, overrideConfig);
}
+ public MergedConfiguration(Configuration globalConfig) {
+ setGlobalConfiguration(globalConfig);
+ }
+
public MergedConfiguration(MergedConfiguration mergedConfiguration) {
setConfiguration(mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration());
@@ -93,6 +99,36 @@
}
/**
+ * Update global configurations.
+ * Merged configuration will automatically be updated.
+ * @param globalConfig New global configuration.
+ */
+ public void setGlobalConfiguration(Configuration globalConfig) {
+ mGlobalConfig.setTo(globalConfig);
+ updateMergedConfig();
+ }
+
+ /**
+ * Update override configurations.
+ * Merged configuration will automatically be updated.
+ * @param overrideConfig New override configuration.
+ */
+ public void setOverrideConfiguration(Configuration overrideConfig) {
+ mOverrideConfig.setTo(overrideConfig);
+ updateMergedConfig();
+ }
+
+ public void setTo(MergedConfiguration config) {
+ setConfiguration(config.mGlobalConfig, config.mOverrideConfig);
+ }
+
+ public void unset() {
+ mGlobalConfig.unset();
+ mOverrideConfig.unset();
+ updateMergedConfig();
+ }
+
+ /**
* @return Stored global configuration value.
*/
@NonNull
@@ -119,4 +155,14 @@
mMergedConfig.setTo(mGlobalConfig);
mMergedConfig.updateFrom(mOverrideConfig);
}
+
+ @Override
+ public String toString() {
+ return "{mGlobalConfig=" + mGlobalConfig + " mOverrideConfig=" + mOverrideConfig + "}";
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "mGlobalConfig=" + mGlobalConfig);
+ pw.println(prefix + "mOverrideConfig=" + mOverrideConfig);
+ }
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1977ef5..b7834823 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5823,34 +5823,6 @@
}
/**
- * Quick invalidation method that simply transforms the dirty rect into the parent's
- * coordinate system, pruning the invalidation if the parent has already been invalidated.
- *
- * @hide
- */
- protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
- if ((mPrivateFlags & PFLAG_DRAWN) != 0
- || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
- dirty.offset(left - mScrollX, top - mScrollY);
- if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
- dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
- }
-
- if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
- dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
-
- if (!getMatrix().isIdentity()) {
- transformRect(dirty);
- }
-
- return mParent;
- }
- }
-
- return null;
- }
-
- /**
* Offset a rectangle that is in a descendant's coordinate
* space into our coordinate space.
* @param descendant A descendant of this view
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index f061370..21123c1 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -330,20 +330,20 @@
@Override
public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
- if (mHostView != null && mHostView.getParent() != null) {
- mHostView.getParent().onDescendantInvalidated(mHostView, target);
- }
- }
+ if (mHostView != null) {
+ if (mHostView instanceof ViewGroup) {
+ // Propagate invalidate through the host...
+ ((ViewGroup) mHostView).onDescendantInvalidated(mHostView, target);
- /**
- * @hide
- */
- @Override
- protected ViewParent damageChildInParent(int left, int top, Rect dirty) {
- if (mHostView instanceof ViewGroup) {
- return ((ViewGroup) mHostView).damageChildInParent(left, top, dirty);
+ // ...and also this view, since it will hold the descendant, and must later
+ // propagate the calls to update display lists if dirty
+ super.onDescendantInvalidated(child, target);
+ } else {
+ // Can't use onDescendantInvalidated because host isn't a ViewGroup - fall back
+ // to invalidating.
+ invalidate();
+ }
}
- return null;
}
@Override
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 869ef71..74f22b3 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -37,19 +37,38 @@
import java.util.List;
/**
- * A concrete BaseAdapter that is backed by an array of arbitrary
- * objects. By default this class expects that the provided resource id references
- * a single TextView. If you want to use a more complex layout, use the constructors that
- * also takes a field id. That field id should reference a TextView in the larger layout
- * resource.
- *
- * <p>However the TextView is referenced, it will be filled with the toString() of each object in
- * the array. You can add lists or arrays of custom objects. Override the toString() method
- * of your objects to determine what text will be displayed for the item in the list.
- *
- * <p>To use something other than TextViews for the array display, for instance, ImageViews,
- * or to have some of data besides toString() results fill the views,
- * override {@link #getView(int, View, ViewGroup)} to return the type of view you want.
+ * You can use this adapter to provide views for an {@link AdapterView},
+ * Returns a view for each object in a collection of data objects you
+ * provide, and can be used with list-based user interface widgets such as
+ * {@link ListView} or {@link Spinner}.
+ * <p>
+ * By default, the array adapter creates a view by calling {@link Object#toString()} on each
+ * data object in the collection you provide, and places the result in a TextView.
+ * You may also customize what type of view is used for the data object in the collection.
+ * To customize what type of view is used for the data object,
+ * override {@link #getView(int, View, ViewGroup)}
+ * and inflate a view resource.
+ * For a code example, see
+ * the <a href="https://developer.android.com/samples/CustomChoiceList/index.html">
+ * CustomChoiceList</a> sample.
+ * </p>
+ * <p>
+ * For an example of using an array adapter with a ListView, see the
+ * <a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">
+ * Adapter Views</a> guide.
+ * </p>
+ * <p>
+ * For an example of using an array adapter with a Spinner, see the
+ * <a href="{@docRoot}guide/topics/ui/controls/spinner.html">Spinners</a> guide.
+ * </p>
+ * <p class="note"><strong>Note:</strong>
+ * If you are considering using array adapter with a ListView, consider using
+ * {@link android.support.v7.widget.RecyclerView} instead.
+ * RecyclerView offers similar features with better performance and more flexibility than
+ * ListView provides.
+ * See the
+ * <a href="https://developer.android.com/guide/topics/ui/layout/recyclerview.html">
+ * Recycler View</a> guide.</p>
*/
public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
/**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 12e35a1..569fe01 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -67,11 +67,77 @@
/**
- * A view that shows items in a vertically scrolling list. The items
- * come from the {@link ListAdapter} associated with this view.
+ * <p>Displays a vertically-scrollable collection of views, where each view is positioned
+ * immediatelybelow the previous view in the list. For a more modern, flexible, and performant
+ * approach to displaying lists, use {@link android.support.v7.widget.RecyclerView}.</p>
*
- * <p>See the <a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>
- * guide.</p>
+ * <p>To display a list, you can include a list view in your layout XML file:</p>
+ *
+ * <pre><ListView
+ * android:id="@+id/list_view"
+ * android:layout_width="match_parent"
+ * android:layout_height="match_parent" /></pre>
+ *
+ * <p>A list view is an <a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">
+ * adapter view</a> that does not know the details, such as type and contents, of the views it
+ * contains. Instead list view requests views on demand from a {@link ListAdapter} as needed,
+ * such as to display new views as the user scrolls up or down.</p>
+ *
+ * <p>In order to display items in the list, call {@link #setAdapter(ListAdapter adapter)}
+ * to associate an adapter with the list. For a simple example, see the discussion of filling an
+ * adapter view with text in the
+ * <a href="{@docRoot}guide/topics/ui/declaring-layout.html#FillingTheLayout">
+ * Layouts</a> guide.</p>
+ *
+ * <p>To display a more custom view for each item in your dataset, implement a ListAdapter.
+ * For example, extend {@link BaseAdapter} and create and configure the view for each data item in
+ * {@code getView(...)}:</p>
+ *
+ * <pre>private class MyAdapter extends BaseAdapter {
+ *
+ * // override other abstract methods here
+ *
+ * @Override
+ * public View getView(int position, View convertView, ViewGroup container) {
+ * if (convertView == null) {
+ * convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
+ * }
+ *
+ * ((TextView) convertView.findViewById(android.R.id.text1))
+ * .setText(getItem(position));
+ * return convertView;
+ * }
+ * }</pre>
+ *
+ * <p class="note">ListView attempts to reuse view objects in order to improve performance and
+ * avoid a lag in response to user scrolls. To take advantage of this feature, check if the
+ * {@code convertView} provided to {@code getView(...)} is null before creating or inflating a new
+ * view object. See
+ * <a href="{@docRoot}training/improving-layouts/smooth-scrolling.html">
+ * Making ListView Scrolling Smooth</a> for more ways to ensure a smooth user experience.</p>
+ *
+ * <p>For a more complete example of creating a custom adapter, see the
+ * <a href="{@docRoot}samples/CustomChoiceList/index.html">
+ * Custom Choice List</a> sample app.</p>
+ *
+ * <p>To specify an action when a user clicks or taps on a single list item, see
+ * <a href="{@docRoot}guide/topics/ui/declaring-layout.html#HandlingUserSelections">
+ * Handling click events</a>.</p>
+ *
+ * <p>To learn how to populate a list view with a CursorAdapter, see the discussion of filling an
+ * adapter view with text in the
+ * <a href="{@docRoot}guide/topics/ui/declaring-layout.html#FillingTheLayout">
+ * Layouts</a> guide.
+ * See <a href="{@docRoot}guide/topics/ui/layout/listview.html">
+ * Using a Loader</a>
+ * to learn how to avoid blocking the main thread when using a cursor.</p>
+ *
+ * <p class="note">Note, many examples use {@link android.app.ListActivity ListActivity}
+ * or {@link android.app.ListFragment ListFragment}
+ * to display a list view. Instead, favor the more flexible approach when writing your own app:
+ * use a more generic Activity subclass or Fragment subclass and add a list view to the layout
+ * or view hierarchy directly. This approach gives you more direct control of the
+ * list view and adapter.</p>
*
* @attr ref android.R.styleable#ListView_entries
* @attr ref android.R.styleable#ListView_divider
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index d046996..f1b19e17 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -427,6 +427,11 @@
String8 clientName(packageUtf.c_str());
sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
+ if (queue == NULL) {
+ jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");
+ return 0;
+ }
+
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3e11368..3898cae 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2332,10 +2332,18 @@
<attr name="importantForAutofill">
<!-- Let the Android System use its heuristics to determine if the view is important for autofill. -->
<flag name="auto" value="0" />
- <!-- Hint the Android System that this view is important for autofill. -->
+ <!-- Hint the Android System that this view is important for autofill,
+ and its children (if any) will be traversed.. -->
<flag name="yes" value="0x1" />
- <!-- Hint the Android System that this view is *not* important for autofill. -->
+ <!-- Hint the Android System that this view is *not* important for autofill,
+ but its children (if any) will be traversed.. -->
<flag name="no" value="0x2" />
+ <!-- Hint the Android System that this view is important for autofill,
+ but its children (if any) will not be traversed. -->
+ <flag name="yesExcludeDescendants" value="0x4" />
+ <!-- Hint the Android System that this view is *not* important for autofill,
+ and its children (if any) will not be traversed. -->
+ <flag name="noExcludeDescendants" value="0x8" />
</attr>
<!-- Boolean that controls whether a view can take focus while in touch mode.
diff --git a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
new file mode 100644
index 0000000..654474c
--- /dev/null
+++ b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.preference;
+
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PreferenceIconSpaceTest {
+
+ private TestPreference mPreference;
+
+ @Mock
+ private ViewGroup mViewGroup;
+ @Mock
+ private ImageView mIconView;
+ @Mock
+ private View mImageFrame;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mViewGroup.findViewById(com.android.internal.R.id.icon_frame))
+ .thenReturn(mImageFrame);
+ when(mViewGroup.findViewById(com.android.internal.R.id.icon))
+ .thenReturn(mIconView);
+
+ mPreference = new TestPreference(InstrumentationRegistry.getTargetContext());
+ }
+
+ @Test
+ public void bindView_iconSpaceReserved_shouldReserveIconSpace() {
+ mPreference.setIconSpaceReserved(true);
+ mPreference.bindView(mViewGroup);
+
+ verify(mIconView).setVisibility(View.INVISIBLE);
+ verify(mImageFrame).setVisibility(View.INVISIBLE);
+ }
+
+ @Test
+ public void bindView_iconSpaceNotReserved_shouldNotReserveIconSpace() {
+ mPreference.setIconSpaceReserved(false);
+ mPreference.bindView(mViewGroup);
+
+ verify(mIconView).setVisibility(View.GONE);
+ verify(mImageFrame).setVisibility(View.GONE);
+ }
+
+ @Test
+ public void bindView_hasIcon_shouldDisplayIcon() {
+ mPreference.setIcon(new ColorDrawable(Color.BLACK));
+ mPreference.bindView(mViewGroup);
+
+ verify(mIconView).setVisibility(View.VISIBLE);
+ verify(mImageFrame).setVisibility(View.VISIBLE);
+ }
+
+ private static class TestPreference extends Preference {
+
+ public TestPreference(Context context) {
+ super(context);
+ }
+
+ public void bindView(View view) {
+ onBindView(view);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 38ab865..4586940 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -37,7 +37,8 @@
/** Tests that ensure appropriate settings are backed up. */
@RunWith(AndroidJUnit4.class)
-@Presubmit
+// TODO(b/37684646): Can re-enable pre-submit once test is fixed.
+//@Presubmit
@SmallTest
public class SettingsBackupTest {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 42fd5d8..aedf6a7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -27,7 +27,6 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.FontListParser;
import android.graphics.fonts.FontRequest;
@@ -99,8 +98,6 @@
static Typeface[] sDefaults;
private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
new LongSparseArray<>(3);
- @GuardedBy("sLock")
- private static FontsContract sFontsContract;
/**
* Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
@@ -221,7 +218,7 @@
// default font instead (nothing we can do now).
FontRequest request = new FontRequest(providerEntry.getAuthority(),
providerEntry.getPackage(), providerEntry.getQuery(), certs);
- Typeface typeface = sFontsContract.getFontOrWarmUpCache(request);
+ Typeface typeface = FontsContract.getFontOrWarmUpCache(request);
return typeface == null ? DEFAULT : typeface;
}
@@ -277,19 +274,6 @@
}
/**
- * Set the application context so we can generate font requests from the provider. This should
- * be called from ActivityThread when the application binds, as we preload fonts.
- * @hide
- */
- public static void setApplicationContext(Context context) {
- synchronized (sLock) {
- if (sFontsContract == null) {
- sFontsContract = new FontsContract(context);
- }
- }
- }
-
- /**
* A builder class for creating new Typeface instance.
*
* <p>
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 5c64566..ea804d0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -17,7 +17,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
import android.annotation.WorkerThread;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
@@ -199,12 +201,14 @@
* {@link Build.VERSION_CODES#N_MR1} will only receive this broadcast if they register for it
* at runtime.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
/**
* Broadcast Action: Indicates the contents of the keychain has changed. Sent when a KeyChain
* entry is added, modified or removed.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED";
/**
@@ -216,6 +220,7 @@
* <li>A CA is added or removed from the trust store</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TRUST_STORE_CHANGED =
"android.security.action.TRUST_STORE_CHANGED";
@@ -223,6 +228,7 @@
* Broadcast Action: Indicates that the access permissions for a private key have changed.
*
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_KEY_ACCESS_CHANGED =
"android.security.action.KEY_ACCESS_CHANGED";
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 052c018..55b74ed 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -28,6 +28,7 @@
#include <ui/ColorSpace.h>
#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <SkBitmap.h>
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 71f9ba25..947adfc 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -19,8 +19,10 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
import android.annotation.StringDef;
import android.annotation.SystemApi;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -90,6 +92,7 @@
* @hide
*/
@SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CHANNEL_BROWSABLE_REQUESTED =
"android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED";
@@ -105,6 +108,7 @@
* integer.</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_REQUEST_CHANNEL_BROWSABLE =
"android.media.tv.action.REQUEST_CHANNEL_BROWSABLE";
@@ -119,6 +123,7 @@
* <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the disabled preview program ID.</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED =
"android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
@@ -133,6 +138,7 @@
* <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the disabled "watch next" program ID.</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED =
"android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
@@ -146,6 +152,7 @@
* <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the ID of the new watch next program.</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
"android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
@@ -163,6 +170,7 @@
* <code>AndroidManifest.xml</code>.</li>
* </ul>
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_INITIALIZE_PROGRAMS =
"android.media.tv.action.INITIALIZE_PROGRAMS";
@@ -2989,6 +2997,8 @@
*/
public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS =
"last_engagement_time_utc_millis";
+
+ private WatchNextPrograms() {}
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 8808988..f516d74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -20,7 +20,9 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -31,10 +33,13 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class BluetoothControllerImplTest extends SysuiTestCase {
private LocalBluetoothManager mMockBluetoothManager;
@@ -47,7 +52,7 @@
@Before
public void setup() throws Exception {
- mTestableLooper = new TestableLooper();
+ mTestableLooper = TestableLooper.get(this);
mMockBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager.class);
mDevices = new ArrayList<>();
mMockDeviceManager = mock(CachedBluetoothDeviceManager.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 45c2054..01ef01b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -411,6 +411,7 @@
import com.android.server.pm.Installer.InstallerException;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
@@ -7818,10 +7819,15 @@
try {
synchronized(this) {
final ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack == null) {
+ if (stack == null || stack.mStackId != PINNED_STACK_ID) {
return false;
}
- return stack.mStackId == PINNED_STACK_ID;
+
+ // If we are animating to fullscreen then we have already dispatched the PIP mode
+ // changed, so we should reflect that check here as well.
+ final PinnedStackWindowController windowController =
+ ((PinnedActivityStack) stack).getWindowContainerController();
+ return !windowController.isAnimatingBoundsToFullscreen();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -11255,9 +11261,13 @@
holder.provider = null;
return holder;
}
- // Don't expose instant app providers
- if (cpr.appInfo.isInstantApp()) {
- return null;
+ // Don't expose providers between normal apps and instant apps
+ try {
+ if (AppGlobals.getPackageManager()
+ .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
+ return null;
+ }
+ } catch (RemoteException e) {
}
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index eeedab8..5f55411 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -62,6 +62,8 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.EMPTY;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@@ -139,6 +141,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Log;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.AppTransitionAnimationSpec;
@@ -240,13 +243,8 @@
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
long pauseTime; // last time we started pausing the activity
long launchTickTime; // base time for launch tick messages
- // TODO: Refactor mLastReportedConfiguration and mLastReportedOverrideConfiguration to use a
- // MergedConfiguration object for clarity.
- private Configuration mLastReportedConfiguration; // configuration activity was last running in
- // Overridden configuration by the activity task
- // WARNING: Reference points to {@link TaskRecord#getMergedOverrideConfig}, so its internal
- // state should never be altered directly.
- private Configuration mLastReportedOverrideConfiguration;
+ // Last configuration reported to the activity in the client process.
+ private MergedConfiguration mLastReportedConfiguration;
private int mLastReportedDisplayId;
CompatibilityInfo compat;// last used compatibility mode
ActivityRecord resultTo; // who started this entry, so will get our reply
@@ -274,11 +272,13 @@
// completed
boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch
int configChangeFlags; // which config values have changed
- boolean keysPaused; // has key dispatching been paused for it?
+ private boolean keysPaused; // has key dispatching been paused for it?
int launchMode; // the launch mode activity attribute.
boolean visible; // does this activity's window need to be shown?
boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
// might hide this activity?
+ private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
+ // process that it is hidden.
boolean sleeping; // have we told the activity to sleep?
boolean nowVisible; // is this activity's window visible?
boolean idle; // has the activity gone idle?
@@ -344,10 +344,7 @@
/**
* Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
*/
- private final Configuration mTmpConfig1 = new Configuration();
- private final Configuration mTmpConfig2 = new Configuration();
- private final Configuration mTmpConfig3 = new Configuration();
- private final Point mTmpPoint = new Point();
+ private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
private static String startingWindowStateToString(int state) {
@@ -398,10 +395,9 @@
pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
- pw.print(prefix); pw.print("mLastReportedConfiguration=");
- pw.println(mLastReportedConfiguration);
- pw.print(prefix); pw.print("mLastReportedOverrideConfiguration=");
- pw.println(mLastReportedOverrideConfiguration);
+ pw.println(prefix + "mLastReportedConfigurations:");
+ mLastReportedConfiguration.dump(pw, prefix + " ");
+
pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
if (!getOverrideConfiguration().equals(EMPTY)) {
pw.println(prefix + "OverrideConfiguration=" + getOverrideConfiguration());
@@ -523,6 +519,9 @@
else TimeUtils.formatDuration(lastVisibleTime, now, pw);
pw.println();
}
+ if (mDeferHidingClient) {
+ pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient);
+ }
if (deferRelaunchUntilPaused || configChangeFlags != 0) {
pw.print(prefix); pw.print("deferRelaunchUntilPaused="); pw.print(deferRelaunchUntilPaused);
pw.print(" configChangeFlags=");
@@ -799,8 +798,7 @@
resolvedType = _resolvedType;
componentSpecified = _componentSpecified;
rootVoiceInteraction = _rootVoiceInteraction;
- mLastReportedConfiguration = new Configuration(_configuration);
- mLastReportedOverrideConfiguration = new Configuration();
+ mLastReportedConfiguration = new MergedConfiguration(_configuration);
resultTo = _resultTo;
resultWho = _resultWho;
requestCode = _reqCode;
@@ -1567,22 +1565,31 @@
return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
}
- void setVisibility(boolean visible) {
- mWindowContainerController.setVisibility(visible, false /* deferHidingClient */);
+ void setDeferHidingClient(boolean deferHidingClient) {
+ if (mDeferHidingClient == deferHidingClient) {
+ return;
+ }
+ mDeferHidingClient = deferHidingClient;
+ if (!mDeferHidingClient && !visible) {
+ // Hiding the client is no longer deferred and the app isn't visible still, go ahead and
+ // update the visibility.
+ setVisibility(false);
+ }
}
- void setVisible(boolean newVisible) {
- setVisible(newVisible, false /* deferHidingClient */);
+ void setVisibility(boolean visible) {
+ mWindowContainerController.setVisibility(visible, mDeferHidingClient);
}
// TODO: Look into merging with #setVisibility()
- void setVisible(boolean newVisible, boolean deferHidingClient) {
+ void setVisible(boolean newVisible) {
visible = newVisible;
+ mDeferHidingClient = !visible && mDeferHidingClient;
if (!visible && mUpdateTaskThumbnailWhenHidden) {
updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
mUpdateTaskThumbnailWhenHidden = false;
}
- mWindowContainerController.setVisibility(visible, deferHidingClient);
+ setVisibility(visible);
final ArrayList<ActivityContainer> containers = mChildContainers;
for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
final ActivityContainer container = containers.get(containerNdx);
@@ -2195,15 +2202,15 @@
* global configuration is sent to the client for this activity.
*/
void setLastReportedGlobalConfiguration(@NonNull Configuration config) {
- mLastReportedConfiguration.setTo(config);
+ mLastReportedConfiguration.setGlobalConfiguration(config);
}
/**
- * Set the last reported merged override configuration to the client. Should be called whenever
+ * Set the last reported configuration to the client. Should be called whenever
* a new merged configuration is sent to the client for this activity.
*/
- void setLastReportedMergedOverrideConfiguration(@NonNull Configuration config) {
- mLastReportedOverrideConfiguration.setTo(config);
+ void setLastReportedConfiguration(@NonNull MergedConfiguration config) {
+ mLastReportedConfiguration.setTo(config);
}
/** Call when override config was sent to the Window Manager to update internal records. */
@@ -2211,7 +2218,7 @@
// we should only set this when we actually report to the activity which is what the method
// setLastReportedMergedOverrideConfiguration() does. Investigate if this is really needed.
void onOverrideConfigurationSent() {
- mLastReportedOverrideConfiguration.setTo(getMergedOverrideConfiguration());
+ mLastReportedConfiguration.setOverrideConfiguration(getMergedOverrideConfiguration());
}
@Override
@@ -2227,18 +2234,20 @@
}
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
- private boolean updateOverrideConfiguration() {
+ private void updateOverrideConfiguration() {
+ mTmpConfig.unset();
computeBounds(mTmpBounds);
if (mTmpBounds.equals(mBounds)) {
- return false;
+ return;
}
+
mBounds.set(mTmpBounds);
// Bounds changed...update configuration to match.
- mTmpConfig1.unset();
- task.computeOverrideConfiguration(mTmpConfig1, mBounds, null /* insetBounds */,
- false /* overrideWidth */, false /* overrideHeight */);
- onOverrideConfigurationChanged(mTmpConfig1);
- return true;
+ if (!mBounds.isEmpty()) {
+ task.computeOverrideConfiguration(mTmpConfig, mBounds, null /* insetBounds */,
+ false /* overrideWidth */, false /* overrideHeight */);
+ }
+ onOverrideConfigurationChanged(mTmpConfig);
}
/**
@@ -2266,12 +2275,12 @@
int maxActivityHeight = containingAppHeight;
if (containingAppWidth < containingAppHeight) {
- // Width is the shorter side, so we use that to figure-out what the max. height should
- // be given the aspect ratio.
+ // Width is the shorter side, so we use that to figure-out what the max. height
+ // should be given the aspect ratio.
maxActivityHeight = (int) ((maxActivityWidth * maxAspectRatio) + 0.5f);
} else {
- // Height is the shorter side, so we use that to figure-out what the max. width should
- // be given the aspect ratio.
+ // Height is the shorter side, so we use that to figure-out what the max. width
+ // should be given the aspect ratio.
maxActivityWidth = (int) ((maxActivityHeight * maxAspectRatio) + 0.5f);
}
@@ -2341,9 +2350,8 @@
// nothing to do. We test the full configuration instead of the global and merged override
// configurations because there are cases (like moving a task to the pinned stack) where
// the combine configurations are equal, but would otherwise differ in the override config
- mTmpConfig1.setTo(mLastReportedConfiguration);
- mTmpConfig1.updateFrom(mLastReportedOverrideConfiguration);
- if (getConfiguration().equals(mTmpConfig1) && !forceNewConfig && !displayChanged) {
+ mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
+ if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration & display unchanged in " + this);
return true;
@@ -2354,18 +2362,12 @@
// Find changes between last reported merged configuration and the current one. This is used
// to decide whether to relaunch an activity or just report a configuration change.
- final int changes = getConfigurationChanges(mTmpConfig1);
-
- // Preserve configuration used to generate this set of configuration changes.
- mTmpConfig3.setTo(mTmpConfig1);
+ final int changes = getConfigurationChanges(mTmpConfig);
// Update last reported values.
- final Configuration newGlobalConfig = service.getGlobalConfiguration();
final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
- mTmpConfig1.setTo(mLastReportedConfiguration);
- mTmpConfig2.setTo(mLastReportedOverrideConfiguration);
- mLastReportedConfiguration.setTo(newGlobalConfig);
- mLastReportedOverrideConfiguration.setTo(newMergedOverrideConfig);
+ mLastReportedConfiguration.setConfiguration(service.getGlobalConfiguration(),
+ newMergedOverrideConfig);
if (changes == 0 && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2399,10 +2401,9 @@
"Checking to restart " + info.name + ": changed=0x"
+ Integer.toHexString(changes) + ", handles=0x"
+ Integer.toHexString(info.getRealConfigChanged())
- + ", newGlobalConfig=" + newGlobalConfig
- + ", newMergedOverrideConfig=" + newMergedOverrideConfig);
+ + ", mLastReportedConfiguration=" + mLastReportedConfiguration);
- if (shouldRelaunchLocked(changes, mTmpConfig3) || forceNewConfig) {
+ if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
configChangeFlags |= changes;
startFreezingScreenLocked(app, globalChanges);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1e8a587..728a3b9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1406,10 +1406,10 @@
prev.state = STOPPING;
} else if ((!prev.visible && !hasVisibleBehindActivity())
|| mService.isSleepingOrShuttingDownLocked()) {
+ // Clear out any deferred client hide we might currently have.
+ prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
- // stopping. Also, set visibility to false to flush any client hide that might have
- // been deferred.
- prev.setVisibility(false);
+ // stopping.
addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */);
}
} else {
@@ -2030,7 +2030,8 @@
// or stopping. This gives it a chance to enter Pip in onPause().
final boolean deferHidingClient = canEnterPictureInPicture
&& r.state != STOPPING && r.state != STOPPED;
- r.setVisible(false, deferHidingClient);
+ r.setDeferHidingClient(deferHidingClient);
+ r.setVisible(false);
switch (r.state) {
case STOPPING:
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index fb8c161..bff3ce3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -162,6 +162,7 @@
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IntArray;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -1443,17 +1444,16 @@
// a Binder interface which would create a new Configuration. Consequently we have to
// always create a new Configuration here.
- final Configuration globalConfiguration =
- new Configuration(mService.getGlobalConfiguration());
- r.setLastReportedGlobalConfiguration(globalConfiguration);
- final Configuration mergedOverrideConfiguration =
- new Configuration(r.getMergedOverrideConfiguration());
- r.setLastReportedMergedOverrideConfiguration(mergedOverrideConfiguration);
+ final MergedConfiguration mergedConfiguration = new MergedConfiguration(
+ mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
+ r.setLastReportedConfiguration(mergedConfiguration);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
- globalConfiguration,
- mergedOverrideConfiguration, r.compat,
+ // TODO: Have this take the merged configuration instead of separate global and
+ // override configs.
+ mergedConfiguration.getGlobalConfiguration(),
+ mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 349180f..d08298b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1180,7 +1180,7 @@
skip = true;
}
if (!skip && r.callerInstantApp
- && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0
+ && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index faa9934..7bbb1fe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4074,14 +4074,26 @@
* action and a {@code android.intent.category.BROWSABLE} category</li>
* </ul>
*/
+ int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid) {
+ return updateFlagsForResolve(flags, userId, intent, callingUid,
+ false /*includeInstantApps*/, false /*onlyExposedExplicitly*/);
+ }
int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid,
boolean includeInstantApps) {
+ return updateFlagsForResolve(flags, userId, intent, callingUid,
+ includeInstantApps, false /*onlyExposedExplicitly*/);
+ }
+ int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid,
+ boolean includeInstantApps, boolean onlyExposedExplicitly) {
// Safe mode means we shouldn't match any third-party components
if (mSafeMode) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
if (getInstantAppPackageName(callingUid) != null) {
// But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
+ if (onlyExposedExplicitly) {
+ flags |= PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY;
+ }
flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
flags |= PackageManager.MATCH_INSTANT;
} else {
@@ -4098,7 +4110,8 @@
|| isSpecialProcess
|| mContext.checkCallingOrSelfPermission(
android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
- flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
+ flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
+ | PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
if (!allowMatchInstant) {
flags &= ~PackageManager.MATCH_INSTANT;
}
@@ -5659,19 +5672,19 @@
}
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
- int flags, int userId, boolean includeInstantApps) {
+ int flags, int userId, boolean resolveForStart) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
- flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
+ flags = updateFlagsForResolve(flags, userId, intent, callingUid, resolveForStart);
enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
- flags, userId, includeInstantApps);
+ flags, userId, resolveForStart);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final ResolveInfo bestChoice =
@@ -6208,14 +6221,14 @@
}
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
- String resolvedType, int flags, int userId, boolean includeInstantApps) {
+ String resolvedType, int flags, int userId, boolean resolveForStart) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
final String instantAppPkgName = getInstantAppPackageName(callingUid);
- flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
+ final String pkgName = intent.getPackage();
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -6224,6 +6237,8 @@
}
}
+ flags = updateFlagsForResolve(flags, userId, intent, callingUid, resolveForStart,
+ comp != null || pkgName != null /*onlyExposedExplicitly*/);
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -6236,6 +6251,8 @@
(flags & PackageManager.MATCH_INSTANT) != 0;
final boolean matchVisibleToInstantAppOnly =
(flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
+ final boolean matchExplicitlyVisibleOnly =
+ (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
final boolean isCallerInstantApp =
instantAppPkgName != null;
final boolean isTargetSameInstantApp =
@@ -6243,8 +6260,14 @@
final boolean isTargetInstantApp =
(ai.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+ final boolean isTargetVisibleToInstantApp =
+ (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ final boolean isTargetExplicitlyVisibleToInstantApp =
+ isTargetVisibleToInstantApp
+ && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
final boolean isTargetHiddenFromInstantApp =
- (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0;
+ !isTargetVisibleToInstantApp
+ || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp);
final boolean blockResolution =
!isTargetSameInstantApp
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
@@ -6263,7 +6286,6 @@
boolean sortResult = false;
boolean addEphemeral = false;
List<ResolveInfo> result;
- final String pkgName = intent.getPackage();
final boolean ephemeralDisabled = isEphemeralDisabled();
synchronized (mPackages) {
if (pkgName == null) {
@@ -6529,7 +6551,7 @@
}
// allow activities that have been explicitly exposed to ephemeral apps
if (!isEphemeralApp
- && ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0)) {
+ && ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
continue;
}
resolveInfos.remove(i);
@@ -7069,16 +7091,16 @@
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
final int callingUid = Binder.getCallingUid();
- return resolveServiceInternal(
- intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
+ return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid);
}
private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
- int userId, int callingUid, boolean includeInstantApps) {
+ int userId, int callingUid) {
if (!sUserManager.exists(userId)) return null;
- flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
+ flags = updateFlagsForResolve(
+ flags, userId, intent, callingUid, false /*includeInstantApps*/);
List<ResolveInfo> query = queryIntentServicesInternal(
- intent, resolvedType, flags, userId, callingUid, includeInstantApps);
+ intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
if (query != null) {
if (query.size() >= 1) {
// If there is more than one service with the same priority,
@@ -7130,7 +7152,7 @@
(si.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
final boolean isTargetHiddenFromInstantApp =
- (si.flags & ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0;
+ (si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0;
final boolean blockResolution =
!isTargetSameInstantApp
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
@@ -7202,7 +7224,7 @@
}
// allow services that have been explicitly exposed to ephemeral apps
if (!isEphemeralApp
- && ((info.serviceInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0)) {
+ && ((info.serviceInfo.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
continue;
}
resolveInfos.remove(i);
@@ -7251,7 +7273,7 @@
(pi.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
final boolean isTargetHiddenFromInstantApp =
- (pi.flags & ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0;
+ (pi.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0;
final boolean blockResolution =
!isTargetSameInstantApp
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
@@ -7323,7 +7345,7 @@
}
// allow providers that have been explicitly exposed to instant applications
if (!isEphemeralApp
- && ((info.providerInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0)) {
+ && ((info.providerInfo.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
continue;
}
resolveInfos.remove(i);
@@ -7684,7 +7706,7 @@
// instant application; filter out non-exposed provider
if (instantAppPkgName != null
&& !isInstantApp
- && (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0) {
+ && (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0) {
return null;
}
// provider not enabled
@@ -12430,16 +12452,21 @@
if (ai == null) {
return null;
}
+ final boolean matchExplicitlyVisibleOnly =
+ (mFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
final boolean matchVisibleToInstantApp =
(mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
- final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
+ final boolean componentVisible =
+ matchVisibleToInstantApp
+ && info.isVisibleToInstantApp()
+ && (!matchExplicitlyVisibleOnly || info.isExplicitlyVisibleToInstantApp());
+ final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
- if (matchVisibleToInstantApp
- && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+ if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
return null;
}
- // throw out ephemeral filters if we're not explicitly requesting them
- if (!isInstantApp && userState.instantApp) {
+ // throw out instant app filters if we're not explicitly requesting them
+ if (!matchInstantApp && userState.instantApp) {
return null;
}
// throw out instant app filters if updates are available; will trigger
@@ -14118,9 +14145,6 @@
synchronized (mPackages) {
boolean result = mSettings.setDefaultBrowserPackageNameLPw(packageName, userId);
if (packageName != null) {
- result |= updateIntentVerificationStatus(packageName,
- PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
- userId);
mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
packageName, userId);
}
@@ -18589,6 +18613,7 @@
destroyAppDataLIF(pkg, userId,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
destroyAppProfilesLIF(pkg, userId);
+ clearDefaultBrowserIfNeededForUser(ps.name, userId);
removeKeystoreDataIfNeeded(nextUserId, ps.appId);
schedulePackageCleaning(ps.name, nextUserId, false);
synchronized (mPackages) {
@@ -19310,12 +19335,18 @@
}
}
+ /** Clears state for all users, and touches intent filter verification policy */
void clearDefaultBrowserIfNeeded(String packageName) {
for (int oneUserId : sUserManager.getUserIds()) {
- String defaultBrowserPackageName = getDefaultBrowserPackageName(oneUserId);
- if (TextUtils.isEmpty(defaultBrowserPackageName)) continue;
+ clearDefaultBrowserIfNeededForUser(packageName, oneUserId);
+ }
+ }
+
+ private void clearDefaultBrowserIfNeededForUser(String packageName, int userId) {
+ final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
+ if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
if (packageName.equals(defaultBrowserPackageName)) {
- setDefaultBrowserPackageName(null, oneUserId);
+ setDefaultBrowserPackageName(null, userId);
}
}
}
@@ -23517,14 +23548,13 @@
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
return resolveIntentInternal(
- intent, resolvedType, flags, userId, true /*includeInstantApps*/);
+ intent, resolvedType, flags, userId, true /*resolveForStart*/);
}
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType,
int flags, int userId, int callingUid) {
- return resolveServiceInternal(
- intent, resolvedType, flags, userId, callingUid, true /*includeInstantApps*/);
+ return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid);
}
@Override
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 554deae..cea031e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1386,7 +1386,11 @@
if (userId == UserHandle.USER_ALL) {
return false;
}
- mDefaultBrowserApp.put(userId, packageName);
+ if (packageName != null) {
+ mDefaultBrowserApp.put(userId, packageName);
+ } else {
+ mDefaultBrowserApp.remove(userId);
+ }
writePackageRestrictionsLPr(userId);
return true;
}
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 364bf28..ebb9450 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -193,6 +193,7 @@
0
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a1b1cd0..60b136f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -674,7 +674,7 @@
if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
wallpaperDestroyed = true;
}
- win.destroyOrSaveSurface();
+ win.destroyOrSaveSurfaceUnchecked();
} while (i > 0);
mService.mDestroySurface.clear();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9d6e033..6cde53a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2141,7 +2141,12 @@
if (mInputMethodWindow == win) {
setInputMethodWindowLocked(null);
}
- win.destroyOrSaveSurface();
+ boolean stopped = win.mAppToken != null ? win.mAppToken.mAppStopped : false;
+ // We set mDestroying=true so AppWindowToken#notifyAppStopped in-to destroy surfaces
+ // will later actually destroy the surface if we do not do so here. Normally we leave
+ // this to the exit animation.
+ win.mDestroying = true;
+ win.destroySurface(false, stopped);
}
// TODO(multidisplay): Magnification is supported only for the default display.
if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9bdcc36..67516c1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2710,7 +2710,7 @@
+ " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
+ " win.mRemoveOnExit=" + mRemoveOnExit);
if (!cleanupOnResume || mRemoveOnExit) {
- destroyOrSaveSurface();
+ destroyOrSaveSurfaceUnchecked();
}
if (mRemoveOnExit) {
removeImmediately();
@@ -2725,7 +2725,10 @@
return destroyedSomething;
}
- void destroyOrSaveSurface() {
+ // Destroy or save the application surface without checking
+ // various indicators of whether the client has released the surface.
+ // This is in general unsafe, and most callers should use {@link #destroySurface}
+ void destroyOrSaveSurfaceUnchecked() {
mSurfaceSaved = shouldSaveSurface();
if (mSurfaceSaved) {
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index b945cf15..2236b59 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -341,7 +341,7 @@
mAnimation.cancel();
mAnimation = null;
mLocalAnimating = false;
- mWin.destroyOrSaveSurface();
+ mWin.destroyOrSaveSurfaceUnchecked();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 97fa9d55..c7b8f02 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
@@ -115,10 +116,12 @@
return null;
}
final ServiceInfo si = list.get(0).serviceInfo;
- if (si.exported) {
- Log.e(TAG, "DeviceAdminService must not be exported: '"
+
+ if (!permission.BIND_DEVICE_ADMIN.equals(si.permission)) {
+ Log.e(TAG, "DeviceAdminService "
+ si.getComponentName().flattenToShortString()
- + "' will be ignored.");
+ + " must be protected with " + permission.BIND_DEVICE_ADMIN
+ + ".");
return null;
}
return si;
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 92534a1..d057eb5 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -53,9 +53,10 @@
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import android.support.test.annotation.UiThreadTest;
import android.support.test.InstrumentationRegistry;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,6 +64,7 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -70,6 +72,8 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class NotificationManagerServiceTest {
private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
@@ -109,7 +113,6 @@
}
@Before
- @UiThreadTest
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNotificationManagerService = new TestableNotificationManagerService(mContext);
@@ -124,7 +127,7 @@
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
// Use this testable looper.
- mTestableLooper = new TestableLooper(false);
+ mTestableLooper = TestableLooper.get(this);
mListener = mNotificationListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
@@ -165,7 +168,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -177,7 +179,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
try {
mBinderService.createNotificationChannels("test_pkg",
@@ -189,7 +190,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_TwoChannels() throws Exception {
final NotificationChannel channel1 =
new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -202,7 +202,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
throws Exception {
final NotificationChannel channel =
@@ -221,7 +220,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
throws Exception {
final NotificationChannel channel1 =
@@ -236,7 +234,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_suspended() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
@@ -249,7 +246,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_blockedChannel() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
@@ -263,7 +259,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_blockedApp() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
@@ -277,7 +272,6 @@
}
@Test
- @UiThreadTest
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -288,7 +282,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -300,7 +293,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -315,7 +307,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -328,7 +319,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -341,7 +331,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -355,7 +344,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -369,7 +357,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -382,7 +369,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -396,7 +382,6 @@
}
@Test
- @UiThreadTest
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -411,7 +396,6 @@
}
@Test
- @UiThreadTest
public void testTvExtenderChannelOverride_onTv() throws Exception {
mNotificationManagerService.setIsTelevision(true);
mNotificationManagerService.setRankingHelper(mRankingHelper);
@@ -427,7 +411,6 @@
}
@Test
- @UiThreadTest
public void testTvExtenderChannelOverride_notOnTv() throws Exception {
mNotificationManagerService.setIsTelevision(false);
mNotificationManagerService.setRankingHelper(mRankingHelper);
@@ -443,7 +426,6 @@
}
@Test
- @UiThreadTest
public void testCreateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -469,7 +451,6 @@
}
@Test
- @UiThreadTest
public void testCreateChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -490,7 +471,6 @@
}
@Test
- @UiThreadTest
public void testUpdateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -509,7 +489,6 @@
}
@Test
- @UiThreadTest
public void testDeleteChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -526,7 +505,6 @@
}
@Test
- @UiThreadTest
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -543,7 +521,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -561,7 +538,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -583,7 +559,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -609,7 +584,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -624,7 +598,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -643,7 +616,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -666,7 +638,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -680,7 +651,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -698,7 +668,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -719,7 +688,6 @@
}
@Test
- @UiThreadTest
public void testHasCompanionDevice_failure() throws Exception {
when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
new IllegalArgumentException());
@@ -727,7 +695,6 @@
}
@Test
- @UiThreadTest
public void testHasCompanionDevice_noService() throws Exception {
mNotificationManagerService = new TestableNotificationManagerService(mContext);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 3f6f8ec..bb453a9 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -843,18 +843,20 @@
updateUsbNotification();
updateAdbNotification();
+ if (mBootCompleted) {
+ Slog.i(TAG, "update state " + mConnected + " " + mConfigured);
+ updateUsbStateBroadcastIfNeeded(false);
+ }
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
}
if (mBootCompleted) {
- Slog.i(TAG, "update state " + mConnected + " " + mConfigured);
if (!mConnected) {
// restore defaults when USB is disconnected
Slog.i(TAG, "Disconnect, setting usb functions to null");
setEnabledFunctions(null, false, false);
}
- updateUsbStateBroadcastIfNeeded(false);
updateUsbFunctions();
} else {
mPendingBootBroadcast = true;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3aeaa29..b8e24f0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -323,9 +323,6 @@
* a String.
*
* <p class="note">
- * Requires the READ_PHONE_STATE permission.
- *
- * <p class="note">
* This was a {@link android.content.Context#sendStickyBroadcast sticky}
* broadcast in version 1.0, but it is no longer sticky.
* Instead, use {@link #getCallState} to synchronously query the current call state.
@@ -335,6 +332,7 @@
* @see #getCallState
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public static final String ACTION_PHONE_STATE_CHANGED =
"android.intent.action.PHONE_STATE";
@@ -939,10 +937,8 @@
* Returns the software version number for the device, for example,
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceSoftwareVersion() {
return getDeviceSoftwareVersion(getSlotIndex());
}
@@ -952,12 +948,10 @@
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @param slotIndex of which deviceID is returned
*/
/** {@hide} */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceSoftwareVersion(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -975,13 +969,11 @@
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceId() {
try {
ITelephony telephony = getITelephony();
@@ -999,15 +991,13 @@
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @param slotIndex of which deviceID is returned
*
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
try {
@@ -1025,10 +1015,8 @@
/**
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getImei() {
return getImei(getSlotIndex());
}
@@ -1037,11 +1025,9 @@
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @param slotIndex of which IMEI is returned
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1057,10 +1043,8 @@
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMeid() {
return getMeid(getSlotIndex());
}
@@ -1068,11 +1052,9 @@
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @param slotIndex of which MEID is returned
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMeid(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1128,13 +1110,13 @@
*<p>
* @return Current location of the device or null if not available.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION}.
- *
* @deprecated use {@link #getAllCellInfo} instead, which returns a superset of this API.
*/
@Deprecated
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.ACCESS_FINE_LOCATION
+ })
public CellLocation getCellLocation() {
try {
ITelephony telephony = getITelephony();
@@ -1166,11 +1148,9 @@
* Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged
* PhoneStateListener.onCellLocationChanged} will be called on location updates.
*
- * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
- * CONTROL_LOCATION_UPDATES}
- *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
public void enableLocationUpdates() {
enableLocationUpdates(getSubId());
}
@@ -1180,12 +1160,10 @@
* {@link PhoneStateListener#onCellLocationChanged
* PhoneStateListener.onCellLocationChanged} will be called on location updates.
*
- * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
- * CONTROL_LOCATION_UPDATES}
- *
* @param subId for which the location updates are enabled
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
public void enableLocationUpdates(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -1200,11 +1178,9 @@
* Disables location update notifications. {@link PhoneStateListener#onCellLocationChanged
* PhoneStateListener.onCellLocationChanged} will be called on location updates.
*
- * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
- * CONTROL_LOCATION_UPDATES}
- *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
public void disableLocationUpdates() {
disableLocationUpdates(getSubId());
}
@@ -1223,15 +1199,13 @@
/**
* Returns the neighboring cell information of the device.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
- *
* @return List of NeighboringCellInfo or null if info unavailable.
*
* @deprecated Use {@link #getAllCellInfo} which returns a superset of the information
* from NeighboringCellInfo.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
public List<NeighboringCellInfo> getNeighboringCellInfo() {
try {
ITelephony telephony = getITelephony();
@@ -1587,14 +1561,12 @@
* invalid subscription ID is pinned to the TelephonyManager, the returned config will contain
* default values.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
- *
* @see CarrierConfigManager#getConfigForSubId(int)
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
*/
@WorkerThread
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public PersistableBundle getCarrierConfig() {
CarrierConfigManager carrierConfigManager = mContext
.getSystemService(CarrierConfigManager.class);
@@ -1754,11 +1726,9 @@
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -1784,10 +1754,6 @@
* If this object has been created with {@link #createForSubscriptionId}, applies to the given
* subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @return the network type
*
* @see #NETWORK_TYPE_UNKNOWN
@@ -1807,6 +1773,7 @@
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getDataNetworkType() {
return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
@@ -1817,12 +1784,9 @@
* @return the network type
*
* @param subId for which network type is returned
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getDataNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -1843,23 +1807,17 @@
/**
* Returns the NETWORK_TYPE_xxxx for voice
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceNetworkType() {
return getVoiceNetworkType(getSubId());
}
/**
* Returns the NETWORK_TYPE_xxxx for voice for a subId
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -2261,10 +2219,8 @@
/**
* Returns the serial number of the SIM, if applicable. Return null if it is
* unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
}
@@ -2274,10 +2230,9 @@
* unavailable.
* <p>
* @param subId for which Sim Serial number is returned
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSimSerialNumber(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2300,12 +2255,9 @@
* @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
* or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getLteOnCdmaMode() {
return getLteOnCdmaMode(getSubId());
}
@@ -2318,12 +2270,9 @@
* @param subId for which radio is LTE on CDMA is returned
* @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
* or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getLteOnCdmaMode(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -2348,10 +2297,8 @@
/**
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSubscriberId() {
return getSubscriberId(getSubId());
}
@@ -2360,13 +2307,11 @@
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone
* for a subscription.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param subId whose subscriber id is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSubscriberId(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2384,10 +2329,8 @@
/**
* Returns the Group Identifier Level1 for a GSM phone.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getGroupIdLevel1() {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2405,13 +2348,11 @@
/**
* Returns the Group Identifier Level1 for a GSM phone for a particular subscription.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param subId whose subscriber id is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getGroupIdLevel1(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2430,15 +2371,13 @@
* Returns the phone number string for line 1, for example, the MSISDN
* for a GSM phone. Return null if it is unavailable.
* <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * OR
- * {@link android.Manifest.permission#READ_SMS}
- * OR
- * {@link android.Manifest.permission#READ_PHONE_NUMBERS}
- * <p>
* The default SMS app can also use this.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.READ_PHONE_NUMBERS
+ })
public String getLine1Number() {
return getLine1Number(getSubId());
}
@@ -2447,18 +2386,16 @@
* Returns the phone number string for line 1, for example, the MSISDN
* for a GSM phone for a particular subscription. Return null if it is unavailable.
* <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * OR
- * {@link android.Manifest.permission#READ_SMS}
- * OR
- * {@link android.Manifest.permission#READ_PHONE_NUMBERS}
- * <p>
* The default SMS app can also use this.
*
* @param subId whose phone number for line 1 is returned
* @hide
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.READ_PHONE_NUMBERS
+ })
public String getLine1Number(int subId) {
String number = null;
try {
@@ -2530,12 +2467,10 @@
/**
* Returns the alphabetic identifier associated with the line 1 number.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
* nobody seems to call this.
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getLine1AlphaTag() {
return getLine1AlphaTag(getSubId());
}
@@ -2544,13 +2479,11 @@
* Returns the alphabetic identifier associated with the line 1 number
* for a subscription.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param subId whose alphabetic identifier associated with line 1 is returned
* nobody seems to call this.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getLine1AlphaTag(int subId) {
String alphaTag = null;
try {
@@ -2599,12 +2532,10 @@
/**
* Returns the MSISDN string.
* for a GSM phone. Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMsisdn() {
return getMsisdn(getSubId());
}
@@ -2612,13 +2543,11 @@
/**
* Returns the MSISDN string.
* for a GSM phone. Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param subId for which msisdn is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMsisdn(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2635,10 +2564,8 @@
/**
* Returns the voice mail number. Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailNumber() {
return getVoiceMailNumber(getSubId());
}
@@ -2646,12 +2573,10 @@
/**
* Returns the voice mail number for a subscription.
* Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param subId whose voice mail number is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailNumber(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2668,25 +2593,21 @@
/**
* Returns the complete voice mail number. Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CALL_PRIVILEGED)
public String getCompleteVoiceMailNumber() {
return getCompleteVoiceMailNumber(getSubId());
}
/**
* Returns the complete voice mail number. Return null if it is unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
*
* @param subId
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CALL_PRIVILEGED)
public String getCompleteVoiceMailNumber(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2757,9 +2678,6 @@
/**
* Returns whether the visual voicemail client is enabled.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- *
* @param phoneAccountHandle the phone account to check for.
* @return {@code true} when the visual voicemail client is enabled for this client
* @hide
@@ -2767,6 +2685,7 @@
* be implemented instead.
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle){
return false;
}
@@ -2804,14 +2723,12 @@
* to the TelephonyManager. Returns {@code null} when there is no package responsible for
* processing visual voicemail for the subscription.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
- *
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
* @see VisualVoicemailService
*/
@Nullable
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVisualVoicemailPackageName() {
try {
ITelephony telephony = getITelephony();
@@ -2971,9 +2888,6 @@
/**
* Send a visual voicemail SMS. The IPC caller must be the current default dialer.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#SEND_SMS SEND_SMS}
- *
* @param phoneAccountHandle The account to send the SMS with.
* @param number The destination number.
* @param port The destination port for data SMS, or 0 for text SMS.
@@ -2985,6 +2899,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.SEND_SMS)
public void sendVisualVoicemailSmsForSubscriber(int subId, String number, int port,
String text, PendingIntent sentIntent) {
try {
@@ -3089,9 +3004,6 @@
/**
* Returns the voice activation state for the given subscriber.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @param subId The subscription id.
*
* @return voiceActivationState for the given subscriber
@@ -3101,6 +3013,7 @@
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceActivationState(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3115,9 +3028,6 @@
/**
* Returns the data activation state for the given subscriber.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @param subId The subscription id.
*
* @return dataActivationState for the given subscriber
@@ -3128,6 +3038,7 @@
* @see #SIM_ACTIVATION_STATE_RESTRICTED
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getDataActivationState(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3142,23 +3053,19 @@
/**
* Returns the voice mail count. Return 0 if unavailable, -1 if there are unread voice messages
* but the count is unknown.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceMessageCount() {
return getVoiceMessageCount(getSubId());
}
/**
* Returns the voice mail count for a subscription. Return 0 if unavailable.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param subId whose voice message count is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceMessageCount(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3176,10 +3083,8 @@
/**
* Retrieves the alphabetic identifier associated with the voice
* mail number.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailAlphaTag() {
return getVoiceMailAlphaTag(getSubId());
}
@@ -3187,13 +3092,11 @@
/**
* Retrieves the alphabetic identifier associated with the voice
* mail number for a subscription.
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param subId whose alphabetic identifier associated with the
* voice mail number is returned
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailAlphaTag(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -3504,23 +3407,18 @@
/**
* Returns the CDMA ERI icon index to display
- *
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getCdmaEriIconIndex() {
return getCdmaEriIconIndex(getSubId());
}
/**
* Returns the CDMA ERI icon index to display for a subscription
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getCdmaEriIconIndex(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3540,11 +3438,9 @@
* 0 - ON
* 1 - FLASHING
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getCdmaEriIconMode() {
return getCdmaEriIconMode(getSubId());
}
@@ -3554,11 +3450,9 @@
* 0 - ON
* 1 - FLASHING
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getCdmaEriIconMode(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3576,11 +3470,9 @@
/**
* Returns the CDMA ERI text,
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getCdmaEriText() {
return getCdmaEriText(getSubId());
}
@@ -3588,11 +3480,9 @@
/**
* Returns the CDMA ERI text, of a subscription
*
- * <p>
- * Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getCdmaEriText(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3675,13 +3565,10 @@
* android.telephony.TelephonyManager#getCellLocation getCellLocation()}
* instead.
*
- * <p>Requires permission:
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
- *
* @return List of {@link android.telephony.CellInfo}; null if cell
* information is unavailable.
- *
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
public List<CellInfo> getAllCellInfo() {
try {
ITelephony telephony = getITelephony();
@@ -4535,11 +4422,9 @@
* Returns an array of Forbidden PLMNs from the USIM App
* Returns null if the query fails.
*
- *
- * <p>Requires that the caller has READ_PHONE_STATE
- *
* @return an array of forbidden PLMNs or null if not available
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String[] getForbiddenPlmns() {
return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
}
@@ -4548,14 +4433,12 @@
* Returns an array of Forbidden PLMNs from the specified SIM App
* Returns null if the query fails.
*
- *
- * <p>Requires that the calling app has READ_PHONE_STATE
- *
* @param subId subscription ID used for authentication
* @param appType the icc application type, like {@link #APPTYPE_USIM}
* @return fplmns an array of forbidden PLMNs
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String[] getForbiddenPlmns(int subId, int appType) {
try {
ITelephony telephony = getITelephony();
@@ -6243,10 +6126,8 @@
/**
* Returns the current {@link ServiceState} information.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public ServiceState getServiceState() {
return getServiceStateForSubscriber(getSubId());
}
diff --git a/tests/testables/src/android/testing/AndroidTestingRunner.java b/tests/testables/src/android/testing/AndroidTestingRunner.java
index 816ed03..a425f70 100644
--- a/tests/testables/src/android/testing/AndroidTestingRunner.java
+++ b/tests/testables/src/android/testing/AndroidTestingRunner.java
@@ -18,7 +18,7 @@
import android.support.test.internal.runner.junit4.statement.RunBefores;
import android.support.test.internal.runner.junit4.statement.UiThreadStatement;
-import android.testing.TestableLooper.LooperStatement;
+import android.testing.TestableLooper.LooperFrameworkMethod;
import android.testing.TestableLooper.RunWithLooper;
import org.junit.After;
@@ -30,6 +30,7 @@
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -49,28 +50,21 @@
@Override
protected Statement methodInvoker(FrameworkMethod method, Object test) {
- return shouldRunOnUiThread(method) ? new UiThreadStatement(
- methodInvokerInt(method, test), true) : methodInvokerInt(method, test);
- }
-
- protected Statement methodInvokerInt(FrameworkMethod method, Object test) {
- RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
- if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
- if (annotation != null) {
- return new LooperStatement(super.methodInvoker(method, test),
- annotation.setAsMainLooper(), test);
- }
- return super.methodInvoker(method, test);
+ method = looperWrap(method, test, method);
+ final Statement statement = super.methodInvoker(method, test);
+ return shouldRunOnUiThread(method) ? new UiThreadStatement(statement, true) : statement;
}
protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
- List befores = this.getTestClass().getAnnotatedMethods(Before.class);
+ List befores = looperWrap(method, target,
+ this.getTestClass().getAnnotatedMethods(Before.class));
return befores.isEmpty() ? statement : new RunBefores(method, statement,
befores, target);
}
protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
- List afters = this.getTestClass().getAnnotatedMethods(After.class);
+ List afters = looperWrap(method, target,
+ this.getTestClass().getAnnotatedMethods(After.class));
return afters.isEmpty() ? statement : new RunAfters(method, statement, afters,
target);
}
@@ -88,6 +82,30 @@
return annotation == null ? 0L : annotation.timeout();
}
+ protected List<FrameworkMethod> looperWrap(FrameworkMethod method, Object test,
+ List<FrameworkMethod> methods) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ methods = new ArrayList<>(methods);
+ for (int i = 0; i < methods.size(); i++) {
+ methods.set(i, LooperFrameworkMethod.get(methods.get(i),
+ annotation.setAsMainLooper(), test));
+ }
+ }
+ return methods;
+ }
+
+ protected FrameworkMethod looperWrap(FrameworkMethod method, Object test,
+ FrameworkMethod base) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ return LooperFrameworkMethod.get(base, annotation.setAsMainLooper(), test);
+ }
+ return base;
+ }
+
public boolean shouldRunOnUiThread(FrameworkMethod method) {
if (mKlass.getAnnotation(UiThreadTest.class) != null) {
return true;
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 8a33cf9..9eddc51 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -15,20 +15,21 @@
package android.testing;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
+import android.os.TestLooperManager;
+import android.support.test.InstrumentationRegistry;
import android.util.ArrayMap;
-import org.junit.runners.model.Statement;
+import org.junit.runners.model.FrameworkMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.Map;
/**
@@ -38,65 +39,35 @@
*/
public class TestableLooper {
- private final Method mNext;
- private final Method mRecycleUnchecked;
-
private Looper mLooper;
private MessageQueue mQueue;
private boolean mMain;
private Object mOriginalMain;
private MessageHandler mMessageHandler;
- private int mParsedCount;
private Handler mHandler;
- private Message mEmptyMessage;
+ private Runnable mEmptyMessage;
+ private TestLooperManager mQueueWrapper;
- public TestableLooper() throws Exception {
- this(true);
+ public TestableLooper(Looper l) throws Exception {
+ this(InstrumentationRegistry.getInstrumentation().acquireLooperManager(l), l);
}
- public TestableLooper(boolean setMyLooper) throws Exception {
- setupQueue(setMyLooper);
- mNext = mQueue.getClass().getDeclaredMethod("next");
- mNext.setAccessible(true);
- mRecycleUnchecked = Message.class.getDeclaredMethod("recycleUnchecked");
- mRecycleUnchecked.setAccessible(true);
+ private TestableLooper(TestLooperManager wrapper, Looper l) throws Exception {
+ mQueueWrapper = wrapper;
+ setupQueue(l);
+ }
+
+ private TestableLooper(Looper looper, boolean b) throws Exception {
+ setupQueue(looper);
}
public Looper getLooper() {
return mLooper;
}
- private void clearLooper() throws NoSuchFieldException, IllegalAccessException {
- Field field = Looper.class.getDeclaredField("sThreadLocal");
- field.setAccessible(true);
- ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
- sThreadLocal.set(null);
- }
-
- private boolean setForCurrentThread() throws NoSuchFieldException, IllegalAccessException {
- if (Looper.myLooper() != mLooper) {
- Field field = Looper.class.getDeclaredField("sThreadLocal");
- field.setAccessible(true);
- ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
- sThreadLocal.set(mLooper);
- return true;
- }
- return false;
- }
-
- private void setupQueue(boolean setMyLooper) throws Exception {
- if (setMyLooper) {
- clearLooper();
- Looper.prepare();
- mLooper = Looper.myLooper();
- } else {
- Constructor<Looper> constructor = Looper.class.getDeclaredConstructor(
- boolean.class);
- constructor.setAccessible(true);
- mLooper = constructor.newInstance(true);
- }
-
+ private void setupQueue(Looper l) throws Exception {
+ mLooper = l;
mQueue = mLooper.getQueue();
mHandler = new Handler(mLooper);
}
@@ -121,9 +92,7 @@
* tests.
*/
public void destroy() throws NoSuchFieldException, IllegalAccessException {
- if (Looper.myLooper() == mLooper) {
- clearLooper();
- }
+ mQueueWrapper.release();
if (mMain && mOriginalMain != null) {
Field field = mLooper.getClass().getDeclaredField("sMainLooper");
field.setAccessible(true);
@@ -156,34 +125,35 @@
private int processQueuedMessages() {
int count = 0;
- mEmptyMessage = mHandler.obtainMessage(1);
- mHandler.sendMessageDelayed(mEmptyMessage, 1);
+ mEmptyMessage = () -> { };
+ mHandler.post(mEmptyMessage);
+ waitForMessage(mQueueWrapper, mHandler, mEmptyMessage);
while (parseMessageInt()) count++;
return count;
}
private boolean parseMessageInt() {
try {
- Message result = (Message) mNext.invoke(mQueue);
+ Message result = mQueueWrapper.next();
if (result != null) {
// This is a break message.
- if (result == mEmptyMessage) {
- mRecycleUnchecked.invoke(result);
+ if (result.getCallback() == mEmptyMessage) {
+ mQueueWrapper.recycle(result);
return false;
}
if (mMessageHandler != null) {
if (mMessageHandler.onMessageHandled(result)) {
result.getTarget().dispatchMessage(result);
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
} else {
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
// Message handler indicated it doesn't want us to continue.
return false;
}
} else {
result.getTarget().dispatchMessage(result);
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
}
} else {
// No messages, don't continue parsing
@@ -199,10 +169,14 @@
* Runs an executable with myLooper set and processes all messages added.
*/
public void runWithLooper(RunnableWithException runnable) throws Exception {
- boolean set = setForCurrentThread();
- runnable.run();
+ new Handler(getLooper()).post(() -> {
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
processAllMessages();
- if (set) clearLooper();
}
public interface RunnableWithException {
@@ -215,39 +189,132 @@
boolean setAsMainLooper() default false;
}
+ private static void waitForMessage(TestLooperManager queueWrapper, Handler handler,
+ Runnable execute) {
+ for (int i = 0; i < 10; i++) {
+ if (!queueWrapper.hasMessages(handler, null, execute)) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (!queueWrapper.hasMessages(handler, null, execute)) {
+ throw new RuntimeException("Message didn't queue...");
+ }
+ }
+
private static final Map<Object, TestableLooper> sLoopers = new ArrayMap<>();
public static TestableLooper get(Object test) {
return sLoopers.get(test);
}
- public static class LooperStatement extends Statement {
- private final boolean mSetAsMain;
- private final Statement mBase;
- private final TestableLooper mLooper;
+ public static class LooperFrameworkMethod extends FrameworkMethod {
+ private HandlerThread mHandlerThread;
- public LooperStatement(Statement base, boolean setAsMain, Object test) {
- mBase = base;
+ private final TestableLooper mTestableLooper;
+ private final Looper mLooper;
+ private final Handler mHandler;
+
+ public LooperFrameworkMethod(FrameworkMethod base, boolean setAsMain, Object test) {
+ super(base.getMethod());
try {
- mLooper = new TestableLooper(false);
- sLoopers.put(test, mLooper);
- mSetAsMain = setAsMain;
+ mLooper = setAsMain ? Looper.getMainLooper() : createLooper();
+ mTestableLooper = new TestableLooper(mLooper, false);
} catch (Exception e) {
throw new RuntimeException(e);
}
+ sLoopers.put(test, mTestableLooper);
+ mHandler = new Handler(mLooper);
+ }
+
+ public LooperFrameworkMethod(TestableLooper other, FrameworkMethod base) {
+ super(base.getMethod());
+ mLooper = other.mLooper;
+ mTestableLooper = other;
+ mHandler = new Handler(mLooper);
+ }
+
+ public static FrameworkMethod get(FrameworkMethod base, boolean setAsMain, Object test) {
+ if (sLoopers.containsKey(test)) {
+ return new LooperFrameworkMethod(sLoopers.get(test), base);
+ }
+ return new LooperFrameworkMethod(base, setAsMain, test);
}
@Override
- public void evaluate() throws Throwable {
- mLooper.setForCurrentThread();
- if (mSetAsMain) {
- mLooper.setAsMainLooper();
+ public Object invokeExplosively(Object target, Object... params) throws Throwable {
+ if (Looper.myLooper() == mLooper) {
+ // Already on the right thread from another statement, just execute then.
+ return super.invokeExplosively(target, params);
+ }
+ boolean set = mTestableLooper.mQueueWrapper == null;
+ if (set) {
+ mTestableLooper.mQueueWrapper = InstrumentationRegistry.getInstrumentation()
+ .acquireLooperManager(mLooper);
+ }
+ try {
+ Object[] ret = new Object[1];
+ // Run the execution on the looper thread.
+ Runnable execute = () -> {
+ try {
+ ret[0] = super.invokeExplosively(target, params);
+ } catch (Throwable throwable) {
+ throw new LooperException(throwable);
+ }
+ };
+ Message m = Message.obtain(mHandler, execute);
+
+ // Dispatch our message.
+ try {
+ mTestableLooper.mQueueWrapper.execute(m);
+ } catch (LooperException e) {
+ throw e.getSource();
+ } catch (RuntimeException re) {
+ // If the TestLooperManager has to post, it will wrap what it throws in a
+ // RuntimeException, make sure we grab the actual source.
+ if (re.getCause() instanceof LooperException) {
+ throw ((LooperException) re.getCause()).getSource();
+ } else {
+ throw re.getCause();
+ }
+ } finally {
+ m.recycle();
+ }
+ return ret[0];
+ } finally {
+ if (set) {
+ mTestableLooper.mQueueWrapper.release();
+ mTestableLooper.mQueueWrapper = null;
+ }
+ }
+ }
+
+ private Looper createLooper() {
+ // TODO: Find way to share these.
+ mHandlerThread = new HandlerThread(TestableLooper.class.getSimpleName());
+ mHandlerThread.start();
+ return mHandlerThread.getLooper();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
+ }
+
+ private static class LooperException extends RuntimeException {
+ private final Throwable mSource;
+
+ public LooperException(Throwable t) {
+ mSource = t;
}
- try {
- mBase.evaluate();
- } finally {
- mLooper.destroy();
+ public Throwable getSource() {
+ return mSource;
}
}
}
diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java
index 18e5fff..12f1d0a 100644
--- a/tests/testables/tests/src/android/testing/TestableLooperTest.java
+++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java
@@ -24,17 +24,16 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.testing.TestableLooper.MessageHandler;
import android.testing.TestableLooper.RunWithLooper;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class TestableLooperTest {
@@ -46,11 +45,6 @@
mTestableLooper = TestableLooper.get(this);
}
- @After
- public void tearDown() throws Exception {
- mTestableLooper.destroy();
- }
-
@Test
public void testMessageExecuted() throws Exception {
Handler h = new Handler();
@@ -133,39 +127,23 @@
@Test
public void testMainLooper() throws Exception {
assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
-
- Looper originalMain = Looper.getMainLooper();
- mTestableLooper.setAsMainLooper();
- assertEquals(Looper.myLooper(), Looper.getMainLooper());
- Runnable r = mock(Runnable.class);
-
- new Handler(Looper.getMainLooper()).post(r);
- mTestableLooper.processAllMessages();
-
- verify(r).run();
- mTestableLooper.destroy();
-
- assertEquals(originalMain, Looper.getMainLooper());
- }
-
- @Test
- public void testNotMyLooper() throws Exception {
- TestableLooper looper = new TestableLooper(false);
-
- assertEquals(Looper.myLooper(), mTestableLooper.getLooper());
- assertNotEquals(Looper.myLooper(), looper.getLooper());
-
Runnable r = mock(Runnable.class);
Runnable r2 = mock(Runnable.class);
- new Handler().post(r);
- new Handler(looper.getLooper()).post(r2);
+ TestableLooper testableLooper = new TestableLooper(Looper.getMainLooper());
- looper.processAllMessages();
- verify(r2).run();
- verify(r, never()).run();
+ try {
+ testableLooper.setMessageHandler(m -> {
+ if (m.getCallback() == r) return true;
+ return false;
+ });
+ new Handler(Looper.getMainLooper()).post(r);
+ testableLooper.processAllMessages();
- mTestableLooper.processAllMessages();
- verify(r).run();
+ verify(r).run();
+ verify(r2, never()).run();
+ } finally {
+ testableLooper.destroy();
+ }
}
@Test