Merge "Implement 2-phase resolution"
diff --git a/Android.mk b/Android.mk
index 6f96803..552103d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -245,12 +245,15 @@
core/java/android/os/IUpdateLock.aidl \
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
- core/java/android/os/storage/IMountService.aidl \
- core/java/android/os/storage/IMountServiceListener.aidl \
- core/java/android/os/storage/IMountShutdownObserver.aidl \
+ core/java/android/os/storage/IStorageManager.aidl \
+ core/java/android/os/storage/IStorageEventListener.aidl \
+ core/java/android/os/storage/IStorageShutdownObserver.aidl \
core/java/android/os/storage/IObbActionListener.aidl \
core/java/android/security/IKeystoreService.aidl \
core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
+ core/java/android/service/autofill/IAutoFillCallback.aidl \
+ core/java/android/service/autofill/IAutoFillManagerService.aidl \
+ core/java/android/service/autofill/IAutoFillService.aidl \
core/java/android/service/carrier/ICarrierService.aidl \
core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
core/java/android/service/carrier/ICarrierMessagingService.aidl \
@@ -485,7 +488,7 @@
../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
-LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES += \
../../system/netd/server/binder/android/net/INetd.aidl \
LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
@@ -517,6 +520,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
android.hardware.thermal@1.0-java-constants \
+ android.hardware.health@1.0-java-constants \
LOCAL_MODULE := framework
diff --git a/CleanSpec.mk b/CleanSpec.mk
index cee8fdb..71e6af7 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -241,6 +241,7 @@
$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit1_intermediates/src/com/android/test/split/feature/R.java)
$(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_intermediates/src/com/android/test/split/feature/R.java)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
index 88cb8e6..f56c763 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -16,7 +16,6 @@
package android.multiuser;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.UserSwitchObserver;
@@ -86,7 +85,7 @@
final Context context = InstrumentationRegistry.getContext();
mUm = UserManager.get(context);
mAm = context.getSystemService(ActivityManager.class);
- mIam = ActivityManagerNative.getDefault();
+ mIam = ActivityManager.getService();
mState = mPerfStatusReporter.getBenchmarkState();
mUsersToRemove = new ArrayList<>();
}
@@ -249,7 +248,7 @@
private void registerUserSwitchObserver(final CountDownLatch switchLatch,
final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ ActivityManager.getService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitchComplete(int newUserId) throws RemoteException {
diff --git a/api/current.txt b/api/current.txt
index f70458b..f585901 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18,6 +18,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -28,6 +29,7 @@
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+ field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -577,8 +579,11 @@
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+ field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+ field public static final int fontStyle = 16844081; // 0x1010531
+ field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
field public static final int foreground = 16843017; // 0x1010109
@@ -3458,6 +3463,7 @@
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public void enterPictureInPictureMode();
+ method public void enterPictureInPictureMode(float);
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3629,6 +3635,7 @@
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
method public void setOverlayWithDecorCaptionEnabled(boolean);
+ method public void setPictureInPictureAspectRatio(float);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3885,6 +3892,7 @@
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
+ method public int getLaunchDisplayId();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -3895,6 +3903,7 @@
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
+ method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -4947,9 +4956,9 @@
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
- method public java.lang.String getNotificationChannel();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
method public void writeToParcel(android.os.Parcel, int);
@@ -5976,6 +5985,7 @@
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6258,6 +6268,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
+ method public int getAutoFillId();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -7897,6 +7908,7 @@
method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method protected final void setPathPermissions(android.content.pm.PathPermission[]);
method protected final void setReadPermission(java.lang.String);
method protected final void setWritePermission(java.lang.String);
@@ -8030,6 +8042,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
method public void releasePersistableUriPermission(android.net.Uri, int);
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
@@ -29330,6 +29343,7 @@
method public void finishBroadcast();
method public java.lang.Object getBroadcastCookie(int);
method public E getBroadcastItem(int);
+ method public java.lang.Object getRegisteredCallbackCookie(int);
method public int getRegisteredCallbackCount();
method public void kill();
method public void onCallbackDied(E);
@@ -32074,10 +32088,10 @@
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
+ field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String EXTRA_LOADING = "loading";
field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
- field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -32182,6 +32196,7 @@
public final class MediaStore {
ctor public MediaStore();
+ method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri getMediaScannerUri();
method public static java.lang.String getVersion(android.content.Context);
field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -34628,6 +34643,33 @@
}
+package android.service.autofill {
+
+ public abstract class AutoFillService extends android.app.Service {
+ ctor public AutoFillService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onConnected();
+ method public void onDisconnected();
+ method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+ }
+
+ public final class FillCallback {
+ method public void onFailure(java.lang.CharSequence);
+ method public void onSuccess(android.service.autofill.FillCallback.FillData);
+ }
+
+ public static final class FillCallback.FillData {
+ }
+
+ public static class FillCallback.FillData.Builder {
+ ctor public FillCallback.FillData.Builder();
+ method public android.service.autofill.FillCallback.FillData build();
+ method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+ }
+
+}
+
package android.service.carrier {
public class CarrierIdentifier implements android.os.Parcelable {
@@ -34830,6 +34872,21 @@
package android.service.notification {
+ public final class Adjustment implements android.os.Parcelable {
+ ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int);
+ ctor protected Adjustment(android.os.Parcel);
+ method public int describeContents();
+ method public java.lang.CharSequence getExplanation();
+ method public int getImportance();
+ method public java.lang.String getKey();
+ method public java.lang.String getPackage();
+ method public android.net.Uri getReference();
+ method public android.os.Bundle getSignals();
+ method public int getUser();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ }
+
public final class Condition implements android.os.Parcelable {
ctor public Condition(android.net.Uri, java.lang.String, int);
ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
@@ -34876,6 +34933,15 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
+ public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+ ctor public NotificationAssistantService();
+ method public final void adjustNotification(android.service.notification.Adjustment);
+ method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -34897,6 +34963,7 @@
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
method public static void requestRebind(android.content.ComponentName);
@@ -34911,6 +34978,25 @@
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ field public static final int REASON_APP_CANCEL = 8; // 0x8
+ field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+ field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+ field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+ field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+ field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+ field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+ field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+ field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+ field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+ field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+ field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+ field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+ field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+ field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -34937,7 +35023,7 @@
}
public class StatusBarNotification implements android.os.Parcelable {
- ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+ ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
method public android.service.notification.StatusBarNotification clone();
method public int describeContents();
@@ -34945,6 +35031,7 @@
method public int getId();
method public java.lang.String getKey();
method public android.app.Notification getNotification();
+ method public android.app.NotificationChannel getNotificationChannel();
method public java.lang.String getOverrideGroupKey();
method public java.lang.String getPackageName();
method public long getPostTime();
@@ -36512,6 +36599,7 @@
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36662,6 +36750,7 @@
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
@@ -37183,8 +37272,12 @@
method public int describeContents();
method public boolean equals(java.lang.Object);
method public int getAsuLevel();
+ method public int getCqi();
method public int getDbm();
method public int getLevel();
+ method public int getRsrp();
+ method public int getRsrq();
+ method public int getRssnr();
method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
@@ -37530,6 +37623,7 @@
public class TelephonyManager {
method public boolean canChangeDtmfToneLength();
+ method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
@@ -37552,6 +37646,7 @@
method public int getNetworkType();
method public int getPhoneCount();
method public int getPhoneType();
+ method public android.telephony.ServiceState getServiceState();
method public java.lang.String getSimCountryIso();
method public java.lang.String getSimOperator();
method public java.lang.String getSimOperatorName();
@@ -40506,6 +40601,45 @@
method public abstract void setValue(T, float);
}
+ public final class Half {
+ method public static short abs(short);
+ method public static short ceil(short);
+ method public static short copySign(short, short);
+ method public static boolean equals(short, short);
+ method public static short floor(short);
+ method public static int getExponent(short);
+ method public static int getSign(short);
+ method public static int getSignificand(short);
+ method public static boolean greater(short, short);
+ method public static boolean greaterEquals(short, short);
+ method public static boolean isInfinite(short);
+ method public static boolean isNaN(short);
+ method public static boolean isNormalized(short);
+ method public static boolean less(short, short);
+ method public static boolean lessEquals(short, short);
+ method public static short max(short, short);
+ method public static short min(short, short);
+ method public static short round(short);
+ method public static float toFloat(short);
+ method public static java.lang.String toHexString(short);
+ method public static java.lang.String toString(short);
+ method public static short trunc(short);
+ method public static short valueOf(float);
+ field public static final short EPSILON = 5120; // 0x1400
+ field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+ field public static final int MAX_EXPONENT = 15; // 0xf
+ field public static final short MAX_VALUE = 31743; // 0x7bff
+ field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+ field public static final short MIN_NORMAL = 1024; // 0x400
+ field public static final short MIN_VALUE = 1; // 0x1
+ field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+ field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+ field public static final short NaN = 32256; // 0x7e00
+ field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+ field public static final short POSITIVE_ZERO = 0; // 0x0
+ field public static final int SIZE = 16; // 0x10
+ }
+
public abstract class IntProperty<T> extends android.util.Property {
ctor public IntProperty(java.lang.String);
method public final void set(T, java.lang.Integer);
@@ -44985,6 +45119,7 @@
field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
field public static final int IME_MASK_ACTION = 255; // 0xff
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
diff --git a/api/system-current.txt b/api/system-current.txt
index 9aebe8f..0314b54 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,6 +28,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -41,6 +42,7 @@
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+ field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -130,6 +132,7 @@
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+ field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
@@ -683,8 +686,11 @@
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+ field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+ field public static final int fontStyle = 16844081; // 0x1010531
+ field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
field public static final int foreground = 16843017; // 0x1010109
@@ -3574,6 +3580,7 @@
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public void enterPictureInPictureMode();
+ method public void enterPictureInPictureMode(float);
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3747,6 +3754,7 @@
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
method public void setOverlayWithDecorCaptionEnabled(boolean);
+ method public void setPictureInPictureAspectRatio(float);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -4016,6 +4024,7 @@
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
+ method public int getLaunchDisplayId();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4026,6 +4035,7 @@
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
+ method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -5099,9 +5109,9 @@
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
- method public java.lang.String getNotificationChannel();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
method public void writeToParcel(android.os.Parcel, int);
@@ -6146,6 +6156,7 @@
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6448,6 +6459,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
+ method public int getAutoFillId();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -8228,6 +8240,7 @@
method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method protected final void setPathPermissions(android.content.pm.PathPermission[]);
method protected final void setReadPermission(java.lang.String);
method protected final void setWritePermission(java.lang.String);
@@ -8361,6 +8374,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
method public void releasePersistableUriPermission(android.net.Uri, int);
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
@@ -31882,6 +31896,7 @@
method public void finishBroadcast();
method public java.lang.Object getBroadcastCookie(int);
method public E getBroadcastItem(int);
+ method public java.lang.Object getRegisteredCallbackCookie(int);
method public int getRegisteredCallbackCount();
method public void kill();
method public void onCallbackDied(E);
@@ -34761,10 +34776,10 @@
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
+ field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String EXTRA_LOADING = "loading";
field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
- field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -34869,6 +34884,7 @@
public final class MediaStore {
ctor public MediaStore();
+ method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri getMediaScannerUri();
method public static java.lang.String getVersion(android.content.Context);
field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -37420,6 +37436,33 @@
}
+package android.service.autofill {
+
+ public abstract class AutoFillService extends android.app.Service {
+ ctor public AutoFillService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onConnected();
+ method public void onDisconnected();
+ method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+ }
+
+ public final class FillCallback {
+ method public void onFailure(java.lang.CharSequence);
+ method public void onSuccess(android.service.autofill.FillCallback.FillData);
+ }
+
+ public static final class FillCallback.FillData {
+ }
+
+ public static class FillCallback.FillData.Builder {
+ ctor public FillCallback.FillData.Builder();
+ method public android.service.autofill.FillCallback.FillData build();
+ method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+ }
+
+}
+
package android.service.carrier {
public class CarrierIdentifier implements android.os.Parcelable {
@@ -37683,6 +37726,15 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
+ public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+ ctor public NotificationAssistantService();
+ method public final void adjustNotification(android.service.notification.Adjustment);
+ method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -37706,6 +37758,7 @@
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
@@ -37723,6 +37776,25 @@
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ field public static final int REASON_APP_CANCEL = 8; // 0x8
+ field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+ field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+ field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+ field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+ field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+ field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+ field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+ field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+ field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+ field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+ field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+ field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+ field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+ field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -37750,39 +37822,8 @@
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
}
- public abstract class NotificationRankerService extends android.service.notification.NotificationListenerService {
- ctor public NotificationRankerService();
- method public final void adjustNotification(android.service.notification.Adjustment);
- method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
- method public final android.os.IBinder onBind(android.content.Intent);
- method public void onNotificationActionClick(java.lang.String, long, int);
- method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
- method public void onNotificationRemoved(java.lang.String, long, int);
- method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
- field public static final int REASON_APP_CANCEL = 8; // 0x8
- field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
- field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
- field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
- field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
- field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
- field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
- field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
- field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
- field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
- field public static final int REASON_SNOOZED = 18; // 0x12
- field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
- field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService";
- }
-
public class StatusBarNotification implements android.os.Parcelable {
- ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+ ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
method public android.service.notification.StatusBarNotification clone();
method public int describeContents();
@@ -37790,6 +37831,7 @@
method public int getId();
method public java.lang.String getKey();
method public android.app.Notification getNotification();
+ method public android.app.NotificationChannel getNotificationChannel();
method public java.lang.String getOverrideGroupKey();
method public java.lang.String getPackageName();
method public long getPostTime();
@@ -39445,6 +39487,7 @@
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -39719,6 +39762,7 @@
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
@@ -40306,8 +40350,12 @@
method public int describeContents();
method public boolean equals(java.lang.Object);
method public int getAsuLevel();
+ method public int getCqi();
method public int getDbm();
method public int getLevel();
+ method public int getRsrp();
+ method public int getRsrq();
+ method public int getRssnr();
method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
@@ -40677,6 +40725,7 @@
method public boolean canChangeDtmfToneLength();
method public int checkCarrierPrivilegesForPackage(java.lang.String);
method public int checkCarrierPrivilegesForPackageAnyPhone(java.lang.String);
+ method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method public void dial(java.lang.String);
method public boolean disableDataConnectivity();
@@ -40714,6 +40763,7 @@
method public int getNetworkType();
method public int getPhoneCount();
method public int getPhoneType();
+ method public android.telephony.ServiceState getServiceState();
method public java.lang.String getSimCountryIso();
method public java.lang.String getSimOperator();
method public java.lang.String getSimOperatorName();
@@ -43718,6 +43768,45 @@
method public abstract void setValue(T, float);
}
+ public final class Half {
+ method public static short abs(short);
+ method public static short ceil(short);
+ method public static short copySign(short, short);
+ method public static boolean equals(short, short);
+ method public static short floor(short);
+ method public static int getExponent(short);
+ method public static int getSign(short);
+ method public static int getSignificand(short);
+ method public static boolean greater(short, short);
+ method public static boolean greaterEquals(short, short);
+ method public static boolean isInfinite(short);
+ method public static boolean isNaN(short);
+ method public static boolean isNormalized(short);
+ method public static boolean less(short, short);
+ method public static boolean lessEquals(short, short);
+ method public static short max(short, short);
+ method public static short min(short, short);
+ method public static short round(short);
+ method public static float toFloat(short);
+ method public static java.lang.String toHexString(short);
+ method public static java.lang.String toString(short);
+ method public static short trunc(short);
+ method public static short valueOf(float);
+ field public static final short EPSILON = 5120; // 0x1400
+ field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+ field public static final int MAX_EXPONENT = 15; // 0xf
+ field public static final short MAX_VALUE = 31743; // 0x7bff
+ field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+ field public static final short MIN_NORMAL = 1024; // 0x400
+ field public static final short MIN_VALUE = 1; // 0x1
+ field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+ field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+ field public static final short NaN = 32256; // 0x7e00
+ field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+ field public static final short POSITIVE_ZERO = 0; // 0x0
+ field public static final int SIZE = 16; // 0x10
+ }
+
public abstract class IntProperty<T> extends android.util.Property {
ctor public IntProperty(java.lang.String);
method public final void set(T, java.lang.Integer);
@@ -48200,6 +48289,7 @@
field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
field public static final int IME_MASK_ACTION = 255; // 0xff
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
diff --git a/api/test-current.txt b/api/test-current.txt
index de57dba..092affc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -18,6 +18,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -28,6 +29,7 @@
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+ field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -577,8 +579,11 @@
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+ field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
+ field public static final int fontStyle = 16844081; // 0x1010531
+ field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
field public static final int foreground = 16843017; // 0x1010109
@@ -3460,6 +3465,7 @@
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public void enterPictureInPictureMode();
+ method public void enterPictureInPictureMode(float);
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3631,6 +3637,7 @@
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
method public void setOverlayWithDecorCaptionEnabled(boolean);
+ method public void setPictureInPictureAspectRatio(float);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3894,6 +3901,7 @@
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
+ method public int getLaunchDisplayId();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -3904,6 +3912,7 @@
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
+ method public android.app.ActivityOptions setLaunchDisplayId(int);
method public void setLaunchStackId(int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
@@ -4957,9 +4966,9 @@
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public java.lang.String getChannel();
method public java.lang.String getGroup();
method public android.graphics.drawable.Icon getLargeIcon();
- method public java.lang.String getNotificationChannel();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
method public void writeToParcel(android.os.Parcel, int);
@@ -5992,6 +6001,7 @@
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6274,6 +6284,7 @@
public static class AssistStructure.ViewNode {
method public float getAlpha();
+ method public int getAutoFillId();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
@@ -7913,6 +7924,7 @@
method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method protected final void setPathPermissions(android.content.pm.PathPermission[]);
method protected final void setReadPermission(java.lang.String);
method protected final void setWritePermission(java.lang.String);
@@ -8047,6 +8059,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
method public void releasePersistableUriPermission(android.net.Uri, int);
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
@@ -29412,6 +29425,7 @@
method public void finishBroadcast();
method public java.lang.Object getBroadcastCookie(int);
method public E getBroadcastItem(int);
+ method public java.lang.Object getRegisteredCallbackCookie(int);
method public int getRegisteredCallbackCount();
method public void kill();
method public void onCallbackDied(E);
@@ -32160,10 +32174,10 @@
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
+ field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String EXTRA_LOADING = "loading";
field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
- field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
}
@@ -32268,6 +32282,7 @@
public final class MediaStore {
ctor public MediaStore();
+ method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri getMediaScannerUri();
method public static java.lang.String getVersion(android.content.Context);
field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
@@ -32764,6 +32779,7 @@
field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
field public static final java.lang.String ANDROID_ID = "android_id";
+ field public static final java.lang.String AUTO_FILL_SERVICE = "auto_fill_service";
field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
field public static final android.net.Uri CONTENT_URI;
@@ -34717,6 +34733,33 @@
}
+package android.service.autofill {
+
+ public abstract class AutoFillService extends android.app.Service {
+ ctor public AutoFillService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onConnected();
+ method public void onDisconnected();
+ method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+ }
+
+ public final class FillCallback {
+ method public void onFailure(java.lang.CharSequence);
+ method public void onSuccess(android.service.autofill.FillCallback.FillData);
+ }
+
+ public static final class FillCallback.FillData {
+ }
+
+ public static class FillCallback.FillData.Builder {
+ ctor public FillCallback.FillData.Builder();
+ method public android.service.autofill.FillCallback.FillData build();
+ method public android.service.autofill.FillCallback.FillData.Builder setTextField(int, java.lang.String);
+ }
+
+}
+
package android.service.carrier {
public class CarrierIdentifier implements android.os.Parcelable {
@@ -34919,6 +34962,21 @@
package android.service.notification {
+ public final class Adjustment implements android.os.Parcelable {
+ ctor public Adjustment(java.lang.String, java.lang.String, int, android.os.Bundle, java.lang.CharSequence, android.net.Uri, int);
+ ctor protected Adjustment(android.os.Parcel);
+ method public int describeContents();
+ method public java.lang.CharSequence getExplanation();
+ method public int getImportance();
+ method public java.lang.String getKey();
+ method public java.lang.String getPackage();
+ method public android.net.Uri getReference();
+ method public android.os.Bundle getSignals();
+ method public int getUser();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ }
+
public final class Condition implements android.os.Parcelable {
ctor public Condition(android.net.Uri, java.lang.String, int);
ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
@@ -34965,6 +35023,15 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
+ public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+ ctor public NotificationAssistantService();
+ method public final void adjustNotification(android.service.notification.Adjustment);
+ method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+ }
+
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -34986,6 +35053,7 @@
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
method public static void requestRebind(android.content.ComponentName);
@@ -35000,6 +35068,25 @@
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+ field public static final int REASON_APP_CANCEL = 8; // 0x8
+ field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
+ field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
+ field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
+ field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
+ field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
+ field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
+ field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
+ field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
+ field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
+ field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+ field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+ field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+ field public static final int REASON_SNOOZED = 18; // 0x12
+ field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
+ field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final int REASON_USER_SWITCH = 19; // 0x13
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
@@ -35026,7 +35113,7 @@
}
public class StatusBarNotification implements android.os.Parcelable {
- ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+ ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
method public android.service.notification.StatusBarNotification clone();
method public int describeContents();
@@ -35034,6 +35121,7 @@
method public int getId();
method public java.lang.String getKey();
method public android.app.Notification getNotification();
+ method public android.app.NotificationChannel getNotificationChannel();
method public java.lang.String getOverrideGroupKey();
method public java.lang.String getPackageName();
method public long getPostTime();
@@ -36601,6 +36689,7 @@
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36751,6 +36840,7 @@
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
@@ -37272,8 +37362,12 @@
method public int describeContents();
method public boolean equals(java.lang.Object);
method public int getAsuLevel();
+ method public int getCqi();
method public int getDbm();
method public int getLevel();
+ method public int getRsrp();
+ method public int getRsrq();
+ method public int getRssnr();
method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
@@ -37619,6 +37713,7 @@
public class TelephonyManager {
method public boolean canChangeDtmfToneLength();
+ method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
@@ -37641,6 +37736,7 @@
method public int getNetworkType();
method public int getPhoneCount();
method public int getPhoneType();
+ method public android.telephony.ServiceState getServiceState();
method public java.lang.String getSimCountryIso();
method public java.lang.String getSimOperator();
method public java.lang.String getSimOperatorName();
@@ -40598,6 +40694,45 @@
method public abstract void setValue(T, float);
}
+ public final class Half {
+ method public static short abs(short);
+ method public static short ceil(short);
+ method public static short copySign(short, short);
+ method public static boolean equals(short, short);
+ method public static short floor(short);
+ method public static int getExponent(short);
+ method public static int getSign(short);
+ method public static int getSignificand(short);
+ method public static boolean greater(short, short);
+ method public static boolean greaterEquals(short, short);
+ method public static boolean isInfinite(short);
+ method public static boolean isNaN(short);
+ method public static boolean isNormalized(short);
+ method public static boolean less(short, short);
+ method public static boolean lessEquals(short, short);
+ method public static short max(short, short);
+ method public static short min(short, short);
+ method public static short round(short);
+ method public static float toFloat(short);
+ method public static java.lang.String toHexString(short);
+ method public static java.lang.String toString(short);
+ method public static short trunc(short);
+ method public static short valueOf(float);
+ field public static final short EPSILON = 5120; // 0x1400
+ field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+ field public static final int MAX_EXPONENT = 15; // 0xf
+ field public static final short MAX_VALUE = 31743; // 0x7bff
+ field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+ field public static final short MIN_NORMAL = 1024; // 0x400
+ field public static final short MIN_VALUE = 1; // 0x1
+ field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+ field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+ field public static final short NaN = 32256; // 0x7e00
+ field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+ field public static final short POSITIVE_ZERO = 0; // 0x0
+ field public static final int SIZE = 16; // 0x10
+ }
+
public abstract class IntProperty<T> extends android.util.Property {
ctor public IntProperty(java.lang.String);
method public final void set(T, java.lang.Integer);
@@ -45231,6 +45366,7 @@
field public static final int IME_FLAG_NO_ENTER_ACTION = 1073741824; // 0x40000000
field public static final int IME_FLAG_NO_EXTRACT_UI = 268435456; // 0x10000000
field public static final int IME_FLAG_NO_FULLSCREEN = 33554432; // 0x2000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
field public static final int IME_MASK_ACTION = 255; // 0xff
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 470a0fa..f003061 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -23,7 +23,6 @@
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManagerNative;
import android.app.IActivityContainer;
import android.app.IActivityController;
import android.app.IActivityManager;
@@ -108,7 +107,7 @@
@Override
public void onRun() throws Exception {
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
if (mAm == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't connect to activity manager; is the system running?");
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 132a4f8..63641a8 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -16,7 +16,7 @@
package com.android.commands.content;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.content.ContentValues;
@@ -433,7 +433,7 @@
public final void execute() {
String providerName = mUri.getAuthority();
try {
- IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IActivityManager activityManager = ActivityManager.getService();
IContentProvider provider = null;
IBinder token = new Binder();
try {
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 31c7421..3ac70d6 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -16,7 +16,7 @@
package com.android.commands.dpm;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
@@ -117,7 +117,7 @@
mUserId = parseInt(arg);
}
if (mUserId == UserHandle.USER_CURRENT) {
- IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IActivityManager activityManager = ActivityManager.getService();
try {
mUserId = activityManager.getCurrentUser().id;
} catch (RemoteException e) {
diff --git a/cmds/locksettings/Android.mk b/cmds/locksettings/Android.mk
new file mode 100644
index 0000000..76766c7
--- /dev/null
+++ b/cmds/locksettings/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := locksettings
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := locksettings
+LOCAL_SRC_FILES := locksettings
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
+
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings
new file mode 100755
index 0000000..c963b23
--- /dev/null
+++ b/cmds/locksettings/locksettings
@@ -0,0 +1,5 @@
+# Script to start "locksettings" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/locksettings.jar
+exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@"
diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
new file mode 100644
index 0000000..1e426d6
--- /dev/null
+++ b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.commands.locksettings;
+
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+
+import com.android.internal.os.BaseCommand;
+import com.android.internal.widget.ILockSettings;
+
+import java.io.FileDescriptor;
+import java.io.PrintStream;
+
+public final class LockSettingsCmd extends BaseCommand {
+
+ private static final String USAGE =
+ "usage: locksettings set-pattern [--old OLD_CREDENTIAL] NEW_PATTERN\n" +
+ " locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" +
+ " locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" +
+ " locksettings clear [--old OLD_CREDENTIAL]\n" +
+ "\n" +
+ "locksettings set-pattern: sets a pattern\n" +
+ " A pattern is specified by a non-separated list of numbers that index the cell\n" +
+ " on the pattern in a 1-based manner in left to right and top to bottom order,\n" +
+ " i.e. the top-left cell is indexed with 1, whereas the bottom-right cell\n" +
+ " is indexed with 9. Example: 1234\n" +
+ "\n" +
+ "locksettings set-pin: sets a PIN\n" +
+ "\n" +
+ "locksettings set-password: sets a password\n" +
+ "\n" +
+ "locksettings clear: clears the unlock credential\n";
+
+ public static void main(String[] args) {
+ (new LockSettingsCmd()).run(args);
+ }
+
+ @Override
+ public void onShowUsage(PrintStream out) {
+ out.println(USAGE);
+ }
+
+ @Override
+ public void onRun() throws Exception {
+ ILockSettings lockSettings = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
+ lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out,
+ FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {});
+ }
+}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 718f141..50f46f4 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -24,7 +24,6 @@
import android.accounts.IAccountManager;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Context;
@@ -1191,7 +1190,7 @@
ClearDataObserver obs = new ClearDataObserver();
try {
- ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId);
+ ActivityManager.getService().clearApplicationUserData(pkg, obs, userId);
synchronized (obs) {
while (!obs.finished) {
try {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index d527ad7..4291c77 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,7 +20,7 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.storage.DiskInfo;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.Log;
@@ -28,7 +28,7 @@
public final class Sm {
private static final String TAG = "Sm";
- IMountService mSm;
+ IStorageManager mSm;
private String[] mArgs;
private int mNextArg;
@@ -55,7 +55,7 @@
throw new IllegalArgumentException();
}
- mSm = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ mSm = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
if (mSm == null) {
throw new RemoteException("Failed to find running mount service");
}
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index 8681166..32b4595 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -16,7 +16,7 @@
package com.android.uiautomator.core;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.app.UiAutomation;
@@ -56,7 +56,7 @@
try {
IContentProvider provider = null;
Cursor cursor = null;
- IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IActivityManager activityManager = ActivityManager.getService();
String providerName = Settings.Secure.CONTENT_URI.getAuthority();
IBinder token = new Binder();
try {
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index ddeb8e7..d98b4ff 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -2,7 +2,6 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.UiAutomation;
@@ -44,7 +43,7 @@
* @see {@link ActivityManager#isUserAMonkey()}
*/
public void setRunAsMonkey(boolean isSet) {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (am == null) {
throw new RuntimeException("Can't manage monkey status; is the system running?");
}
diff --git a/compiled-classes-phone b/compiled-classes-phone
index 8428e41..f09bad9 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -174,9 +174,6 @@
android.app.ActivityManager$TaskThumbnailInfo$1
android.app.ActivityManagerInternal
android.app.ActivityManagerInternal$SleepToken
-android.app.ActivityManagerNative
-android.app.ActivityManagerNative$1
-android.app.ActivityManagerProxy
android.app.ActivityOptions
android.app.ActivityOptions$OnAnimationFinishedListener
android.app.ActivityOptions$OnAnimationStartedListener
@@ -3226,17 +3223,17 @@
android.os.health.SystemHealthManager
android.os.storage.DiskInfo
android.os.storage.DiskInfo$1
-android.os.storage.IMountService
-android.os.storage.IMountService$Stub
-android.os.storage.IMountService$Stub$Proxy
-android.os.storage.IMountServiceListener
-android.os.storage.IMountServiceListener$Stub
-android.os.storage.IMountServiceListener$Stub$Proxy
-android.os.storage.IMountShutdownObserver
+android.os.storage.IStorageManager
+android.os.storage.IStorageManager$Stub
+android.os.storage.IStorageManager$Stub$Proxy
+android.os.storage.IStorageEventListener
+android.os.storage.IStorageEventListener$Stub
+android.os.storage.IStorageEventListener$Stub$Proxy
+android.os.storage.IStorageShutdownObserver
android.os.storage.IObbActionListener
android.os.storage.IObbActionListener$Stub
-android.os.storage.MountServiceInternal
-android.os.storage.MountServiceInternal$ExternalStorageMountPolicy
+android.os.storage.StorageManagerInternal
+android.os.storage.StorageManagerInternal$ExternalStorageMountPolicy
android.os.storage.StorageEventListener
android.os.storage.StorageManager
android.os.storage.StorageManager$ObbActionListener
@@ -3610,9 +3607,9 @@
android.service.notification.NotificationListenerService$Ranking
android.service.notification.NotificationListenerService$RankingMap
android.service.notification.NotificationListenerService$RankingMap$1
-android.service.notification.NotificationRankerService
-android.service.notification.NotificationRankerService$MyHandler
-android.service.notification.NotificationRankerService$NotificationRankingServiceWrapper
+android.service.notification.NotificationAssistantService
+android.service.notification.NotificationAssistantService$MyHandler
+android.service.notification.NotificationAssistantService$NotificationRankingServiceWrapper
android.service.notification.NotificationRankingUpdate
android.service.notification.NotificationRankingUpdate$1
android.service.notification.StatusBarNotification
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index aed7a36..8c71f50 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -18,7 +18,7 @@
import com.google.android.collect.Sets;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
@@ -141,8 +141,8 @@
try {
IBinder activityToken = getActivityToken();
- mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
- mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+ mCallingUid = ActivityManager.getService().getLaunchedFromUid(activityToken);
+ mCallingPackage = ActivityManager.getService().getLaunchedFromPackage(
activityToken);
if (mCallingUid != 0 && mCallingPackage != null) {
Bundle restrictions = UserManager.get(this)
diff --git a/core/java/android/annotation/HalfFloat.java b/core/java/android/annotation/HalfFloat.java
new file mode 100644
index 0000000..d3e9f08
--- /dev/null
+++ b/core/java/android/annotation/HalfFloat.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * <p>Denotes that the annotated element represents a half-precision floating point
+ * value. Such values are stored in short data types and can be manipulated with
+ * the {@link android.util.Half} class. If applied to an array of short, every
+ * element in the array represents a half-precision float.</p>
+ *
+ * <p>Example:</p>
+ *
+ * <pre>{@code
+ * public abstract void setPosition(@HalfFloat short x, @HalfFloat short y, @HalfFloat short z);
+ * }</pre>
+ *
+ * @see android.util.Half
+ * @see android.util.Half#valueOf(float)
+ * @see android.util.Half#toFloat(short)
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+public @interface HalfFloat {
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0552d34..58f5a78 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1494,22 +1494,22 @@
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
v.setOnFocusChangeListener(null);
- final View focused = mFocusRoot.findFocus();
- if (focused != null) {
- focused.setOnFocusChangeListener(this);
- } else {
- mFocusRoot.post(this);
- }
+ mFocusRoot.post(this);
}
}
@Override
public void run() {
- if (mContainer != null) {
- mContainer.setTouchscreenBlocksFocus(true);
- }
- if (mToolbar != null) {
- mToolbar.setTouchscreenBlocksFocus(true);
+ final View focused = mFocusRoot.findFocus();
+ if (focused != null) {
+ focused.setOnFocusChangeListener(this);
+ } else {
+ if (mContainer != null) {
+ mContainer.setTouchscreenBlocksFocus(true);
+ }
+ if (mToolbar != null) {
+ mToolbar.setTouchscreenBlocksFocus(true);
+ }
}
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index b3e2f57..64e5dfc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -53,7 +53,6 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
-import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -70,6 +69,9 @@
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.autofill.FillableInputField;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.IAutoFillCallback;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -90,8 +92,6 @@
import android.view.ContextThemeWrapper;
import android.view.DragAndDropPermissions;
import android.view.DragEvent;
-import android.view.InputDevice;
-import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -113,9 +113,11 @@
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
+import android.widget.EditText;
import android.widget.Toast;
import android.widget.Toolbar;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
@@ -802,11 +804,13 @@
private boolean mReleased;
private boolean mUpdated;
}
- private final ArrayList<ManagedCursor> mManagedCursors =
- new ArrayList<ManagedCursor>();
- // protected by synchronized (this)
+ @GuardedBy("mManagedCursors")
+ private final ArrayList<ManagedCursor> mManagedCursors = new ArrayList<>();
+
+ @GuardedBy("this")
int mResultCode = RESULT_CANCELED;
+ @GuardedBy("this")
Intent mResultData = null;
private TranslucentConversionListener mTranslucentCallback;
@@ -837,6 +841,9 @@
private boolean mHasCurrentPermissionsRequest;
private boolean mEatKeyUpEvent;
+ @GuardedBy("this")
+ private IAutoFillCallback mAutoFillCallback;
+
private static native String getDlWarning();
/** Return the intent that started this activity. */
@@ -1306,7 +1313,7 @@
public boolean isVoiceInteractionRoot() {
try {
return mVoiceInteractor != null
- && ActivityManagerNative.getDefault().isRootVoiceInteraction(mToken);
+ && ActivityManager.getService().isRootVoiceInteraction(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1329,7 +1336,7 @@
*/
public boolean isLocalVoiceInteractionSupported() {
try {
- return ActivityManagerNative.getDefault().supportsLocalVoiceInteraction();
+ return ActivityManager.getService().supportsLocalVoiceInteraction();
} catch (RemoteException re) {
}
return false;
@@ -1343,7 +1350,7 @@
*/
public void startLocalVoiceInteraction(Bundle privateOptions) {
try {
- ActivityManagerNative.getDefault().startLocalVoiceInteraction(mToken, privateOptions);
+ ActivityManager.getService().startLocalVoiceInteraction(mToken, privateOptions);
} catch (RemoteException re) {
}
}
@@ -1372,7 +1379,7 @@
*/
public void stopLocalVoiceInteraction() {
try {
- ActivityManagerNative.getDefault().stopLocalVoiceInteraction(mToken);
+ ActivityManager.getService().stopLocalVoiceInteraction(mToken);
} catch (RemoteException re) {
}
}
@@ -1688,6 +1695,53 @@
}
/**
+ * Lazily gets the {@code IAutoFillCallback} for this activitity.
+ *
+ * <p>This callback is used by the {@link AutoFillService} app to auto-fill the activity fields.
+ */
+ IAutoFillCallback getAutoFillCallback() {
+ synchronized (this) {
+ if (mAutoFillCallback == null) {
+ mAutoFillCallback = new IAutoFillCallback.Stub() {
+ @Override
+ public void autofill(@SuppressWarnings("rawtypes") List fields)
+ throws RemoteException {
+ runOnUiThread(() -> {
+ final View root = getWindow().getDecorView().getRootView();
+ for (Object field : fields) {
+ if (!(field instanceof FillableInputField)) {
+ Slog.w(TAG, "autofill(): invalid type " + field.getClass());
+ continue;
+ }
+ FillableInputField autoFillField = (FillableInputField) field;
+ final int viewId = autoFillField.getId();
+ final View view = root.findViewByAccessibilityIdTraversal(viewId);
+ // TODO: should handle other types of view as well, but that will
+ // require:
+ // - a new interface like AutoFillable
+ // - a way for the views to define the type of the autofield value
+ if ((view instanceof EditText)) {
+ ((EditText) view).setText(autoFillField.getValue());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void showError(String message) {
+ runOnUiThread(() -> {
+ // TODO: temporary show a toast until it uses the Snack bar.
+ Toast.makeText(Activity.this, "Auto-fill request failed: " + message,
+ Toast.LENGTH_LONG).show();
+ });
+ }
+ };
+ }
+ }
+ return mAutoFillCallback;
+ }
+
+ /**
* Request the Keyboard Shortcuts screen to show up. This will trigger
* {@link #onProvideKeyboardShortcuts} to retrieve the shortcuts for the foreground activity.
*/
@@ -1744,7 +1798,7 @@
*/
public boolean showAssist(Bundle args) {
try {
- return ActivityManagerNative.getDefault().showAssistFromActivity(mToken, args);
+ return ActivityManager.getService().showAssistFromActivity(mToken, args);
} catch (RemoteException e) {
}
return false;
@@ -1860,7 +1914,7 @@
if (mDoReportFullyDrawn) {
mDoReportFullyDrawn = false;
try {
- ActivityManagerNative.getDefault().reportActivityFullyDrawn(mToken);
+ ActivityManager.getService().reportActivityFullyDrawn(mToken);
} catch (RemoteException e) {
}
}
@@ -1886,7 +1940,7 @@
*/
public boolean isInMultiWindowMode() {
try {
- return ActivityManagerNative.getDefault().isInMultiWindowMode(mToken);
+ return ActivityManager.getService().isInMultiWindowMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1911,7 +1965,7 @@
*/
public boolean isInPictureInPictureMode() {
try {
- return ActivityManagerNative.getDefault().isInPictureInPictureMode(mToken);
+ return ActivityManager.getService().isInPictureInPictureMode(mToken);
} catch (RemoteException e) {
}
return false;
@@ -1923,7 +1977,33 @@
*/
public void enterPictureInPictureMode() {
try {
- ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
+ ActivityManager.getService().enterPictureInPictureMode(mToken);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Puts the activity in picture-in-picture mode with a given aspect ratio.
+ * @see android.R.attr#supportsPictureInPicture
+ *
+ * @param aspectRatio the new aspect ratio of the picture-in-picture.
+ */
+ public void enterPictureInPictureMode(float aspectRatio) {
+ try {
+ ActivityManagerNative.getDefault().enterPictureInPictureModeWithAspectRatio(mToken,
+ aspectRatio);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Updates the aspect ratio of the current picture-in-picture activity.
+ *
+ * @param aspectRatio the new aspect ratio of the picture-in-picture.
+ */
+ public void setPictureInPictureAspectRatio(float aspectRatio) {
+ try {
+ ActivityManagerNative.getDefault().setPictureInPictureAspectRatio(mToken, aspectRatio);
} catch (RemoteException e) {
}
}
@@ -2957,7 +3037,7 @@
*/
@Override
public void exitFreeformMode() throws RemoteException {
- ActivityManagerNative.getDefault().exitFreeformMode(mToken);
+ ActivityManager.getService().exitFreeformMode(mToken);
}
/** Returns the current stack Id for the window.
@@ -2965,7 +3045,7 @@
*/
@Override
public int getWindowStackId() throws RemoteException {
- return ActivityManagerNative.getDefault().getActivityStackId(mToken);
+ return ActivityManager.getService().getActivityStackId(mToken);
}
/**
@@ -4453,7 +4533,7 @@
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityIntentSender(mMainThread.getApplicationThread(), intent,
fillInIntent, resolvedType, mToken, who,
requestCode, flagsMask, flagsValues, options);
@@ -4683,7 +4763,7 @@
}
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(this);
- result = ActivityManagerNative.getDefault()
+ result = ActivityManager.getService()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken,
mEmbeddedID, requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -4754,7 +4834,7 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(this);
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.startNextMatchingActivity(mToken, intent, options);
} catch (RemoteException e) {
// Empty
@@ -4952,7 +5032,7 @@
*/
public void overridePendingTransition(int enterAnim, int exitAnim) {
try {
- ActivityManagerNative.getDefault().overridePendingTransition(
+ ActivityManager.getService().overridePendingTransition(
mToken, getPackageName(), enterAnim, exitAnim);
} catch (RemoteException e) {
}
@@ -5077,7 +5157,7 @@
@Nullable
public String getCallingPackage() {
try {
- return ActivityManagerNative.getDefault().getCallingPackage(mToken);
+ return ActivityManager.getService().getCallingPackage(mToken);
} catch (RemoteException e) {
return null;
}
@@ -5100,7 +5180,7 @@
@Nullable
public ComponentName getCallingActivity() {
try {
- return ActivityManagerNative.getDefault().getCallingActivity(mToken);
+ return ActivityManager.getService().getCallingActivity(mToken);
} catch (RemoteException e) {
return null;
}
@@ -5185,7 +5265,7 @@
throw new IllegalStateException("Must be called from main thread");
}
try {
- ActivityManagerNative.getDefault().requestActivityRelaunch(mToken);
+ ActivityManager.getService().requestActivityRelaunch(mToken);
} catch (RemoteException e) {
}
}
@@ -5207,7 +5287,7 @@
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
- if (ActivityManagerNative.getDefault()
+ if (ActivityManager.getService()
.finishActivity(mToken, resultCode, resultData, finishTask)) {
mFinished = true;
}
@@ -5250,7 +5330,7 @@
throw new IllegalStateException("Can not be called to deliver a result");
}
try {
- if (ActivityManagerNative.getDefault().finishActivityAffinity(mToken)) {
+ if (ActivityManager.getService().finishActivityAffinity(mToken)) {
mFinished = true;
}
} catch (RemoteException e) {
@@ -5296,7 +5376,7 @@
public void finishActivity(int requestCode) {
if (mParent == null) {
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.finishSubActivity(mToken, mEmbeddedID, requestCode);
} catch (RemoteException e) {
// Empty
@@ -5316,7 +5396,7 @@
*/
public void finishActivityFromChild(@NonNull Activity child, int requestCode) {
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.finishSubActivity(mToken, child.mEmbeddedID, requestCode);
} catch (RemoteException e) {
// Empty
@@ -5344,7 +5424,7 @@
*/
public boolean releaseInstance() {
try {
- return ActivityManagerNative.getDefault().releaseActivityInstance(mToken);
+ return ActivityManager.getService().releaseActivityInstance(mToken);
} catch (RemoteException e) {
// Empty
}
@@ -5434,7 +5514,7 @@
try {
data.prepareToLeaveProcess(this);
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
mParent == null ? mToken : mParent.mToken,
mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null,
@@ -5459,7 +5539,7 @@
public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
if (mParent == null) {
try {
- ActivityManagerNative.getDefault().setRequestedOrientation(
+ ActivityManager.getService().setRequestedOrientation(
mToken, requestedOrientation);
} catch (RemoteException e) {
// Empty
@@ -5482,7 +5562,7 @@
public int getRequestedOrientation() {
if (mParent == null) {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getRequestedOrientation(mToken);
} catch (RemoteException e) {
// Empty
@@ -5501,7 +5581,7 @@
*/
public int getTaskId() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getTaskForActivity(mToken, false);
} catch (RemoteException e) {
return -1;
@@ -5516,7 +5596,7 @@
*/
public boolean isTaskRoot() {
try {
- return ActivityManagerNative.getDefault().getTaskForActivity(mToken, true) >= 0;
+ return ActivityManager.getService().getTaskForActivity(mToken, true) >= 0;
} catch (RemoteException e) {
return false;
}
@@ -5535,7 +5615,7 @@
*/
public boolean moveTaskToBack(boolean nonRoot) {
try {
- return ActivityManagerNative.getDefault().moveActivityTaskToBack(
+ return ActivityManager.getService().moveActivityTaskToBack(
mToken, nonRoot);
} catch (RemoteException e) {
// Empty
@@ -5706,7 +5786,7 @@
}
}
try {
- ActivityManagerNative.getDefault().setTaskDescription(mToken, mTaskDescription);
+ ActivityManager.getService().setTaskDescription(mToken, mTaskDescription);
} catch (RemoteException e) {
}
}
@@ -5948,6 +6028,11 @@
getWindow().peekDecorView().getViewRootImpl().dump(prefix, fd, writer, args);
}
+ if (mAutoFillCallback != null) {
+ writer.print(prefix); writer.print("mAutoFillCallback: " );
+ writer.println(mAutoFillCallback);
+ }
+
mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
}
@@ -5964,7 +6049,7 @@
*/
public boolean isImmersive() {
try {
- return ActivityManagerNative.getDefault().isImmersive(mToken);
+ return ActivityManager.getService().isImmersive(mToken);
} catch (RemoteException e) {
return false;
}
@@ -5982,7 +6067,7 @@
return false;
}
try {
- return ActivityManagerNative.getDefault().isTopOfTask(getActivityToken());
+ return ActivityManager.getService().isTopOfTask(getActivityToken());
} catch (RemoteException e) {
return false;
}
@@ -6008,7 +6093,7 @@
public void convertFromTranslucent() {
try {
mTranslucentCallback = null;
- if (ActivityManagerNative.getDefault().convertFromTranslucent(mToken)) {
+ if (ActivityManager.getService().convertFromTranslucent(mToken)) {
WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, true);
}
} catch (RemoteException e) {
@@ -6047,7 +6132,7 @@
boolean drawComplete;
try {
mTranslucentCallback = callback;
- mChangeCanvasToTranslucent = ActivityManagerNative.getDefault().convertToTranslucent(
+ mChangeCanvasToTranslucent = ActivityManager.getService().convertToTranslucent(
mToken, options == null ? null : options.toBundle());
WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false);
drawComplete = true;
@@ -6093,7 +6178,7 @@
ActivityOptions getActivityOptions() {
try {
return ActivityOptions.fromBundle(
- ActivityManagerNative.getDefault().getActivityOptions(mToken));
+ ActivityManager.getService().getActivityOptions(mToken));
} catch (RemoteException e) {
}
return null;
@@ -6137,7 +6222,7 @@
visible = false;
}
try {
- mVisibleBehind = ActivityManagerNative.getDefault()
+ mVisibleBehind = ActivityManager.getService()
.requestVisibleBehind(mToken, visible) && visible;
} catch (RemoteException e) {
mVisibleBehind = false;
@@ -6178,7 +6263,7 @@
@SystemApi
public boolean isBackgroundVisibleBehind() {
try {
- return ActivityManagerNative.getDefault().isBackgroundVisibleBehind(mToken);
+ return ActivityManager.getService().isBackgroundVisibleBehind(mToken);
} catch (RemoteException e) {
}
return false;
@@ -6235,7 +6320,7 @@
*/
public void setImmersive(boolean i) {
try {
- ActivityManagerNative.getDefault().setImmersive(mToken, i);
+ ActivityManager.getService().setImmersive(mToken, i);
} catch (RemoteException e) {
// pass
}
@@ -6299,7 +6384,7 @@
public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)
throws PackageManager.NameNotFoundException {
try {
- if (ActivityManagerNative.getDefault().setVrMode(mToken, enabled, requestedComponent)
+ if (ActivityManager.getService().setVrMode(mToken, enabled, requestedComponent)
!= 0) {
throw new PackageManager.NameNotFoundException(
requestedComponent.flattenToString());
@@ -6420,7 +6505,7 @@
if (info.taskAffinity == null) {
return false;
}
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.shouldUpRecreateTask(mToken, info.taskAffinity);
} catch (RemoteException e) {
return false;
@@ -6473,7 +6558,7 @@
}
try {
upIntent.prepareToLeaveProcess(this);
- return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
+ return ActivityManager.getService().navigateUpTo(mToken, upIntent,
resultCode, resultData);
} catch (RemoteException e) {
return false;
@@ -6989,7 +7074,7 @@
*/
public void startLockTask() {
try {
- ActivityManagerNative.getDefault().startLockTaskModeByToken(mToken);
+ ActivityManager.getService().startLockTaskModeByToken(mToken);
} catch (RemoteException e) {
}
}
@@ -7013,7 +7098,7 @@
*/
public void stopLockTask() {
try {
- ActivityManagerNative.getDefault().stopLockTaskMode();
+ ActivityManager.getService().stopLockTaskMode();
} catch (RemoteException e) {
}
}
@@ -7025,7 +7110,7 @@
*/
public void showLockTaskEscapeMessage() {
try {
- ActivityManagerNative.getDefault().showLockTaskEscapeMessage(mToken);
+ ActivityManager.getService().showLockTaskEscapeMessage(mToken);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9af7d8b..65f74d1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -36,6 +36,7 @@
import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
+import com.android.server.LocalServices;
import android.content.ComponentName;
import android.content.Context;
@@ -89,35 +90,22 @@
private final Context mContext;
private final Handler mHandler;
+ private static volatile boolean sSystemReady = false;
+
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
- final int mImportanceCutpoint;
- int mLastImportance;
- UidObserver(OnUidImportanceListener listener, int importanceCutpoint) {
+ UidObserver(OnUidImportanceListener listener) {
mListener = listener;
- mImportanceCutpoint = importanceCutpoint;
}
@Override
public void onUidStateChanged(int uid, int procState) {
- final boolean lastAboveCut = mLastImportance <= mImportanceCutpoint;
- final int importance = RunningAppProcessInfo.procStateToImportance(procState);
- final boolean newAboveCut = importance <= mImportanceCutpoint;
- /*
- Log.d(TAG, "Uid " + uid + " state change from " + mLastImportance + " to "
- + importance + " @ cut " + mImportanceCutpoint
- + ": lastAbove=" + lastAboveCut + " newAbove=" + newAboveCut);
- */
- mLastImportance = importance;
- if (lastAboveCut != newAboveCut) {
- mListener.onUidImportance(uid, importance);
- }
+ mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportance(procState));
}
@Override
- public void onUidGone(int uid) {
- mLastImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
+ public void onUidGone(int uid, boolean disabled) {
mListener.onUidImportance(uid, RunningAppProcessInfo.IMPORTANCE_GONE);
}
@@ -126,7 +114,7 @@
}
@Override
- public void onUidIdle(int uid) {
+ public void onUidIdle(int uid, boolean disabled) {
}
}
@@ -380,8 +368,8 @@
/** @hide User operation call: one of related users cannot be stopped. */
public static final int USER_OP_ERROR_RELATED_USERS_CANNOT_STOP = -4;
- /** @hide Process does not exist. */
- public static final int PROCESS_STATE_NONEXISTENT = -1;
+ /** @hide Not a real process state. */
+ public static final int PROCESS_STATE_UNKNOWN = -1;
/** @hide Process is a persistent system process. */
public static final int PROCESS_STATE_PERSISTENT = 0;
@@ -442,11 +430,14 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+ /** @hide Process does not exist. */
+ public static final int PROCESS_STATE_NONEXISTENT = 17;
+
/** @hide The lowest process state number */
- public static final int MIN_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
+ public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
/** @hide The highest process state number */
- public static final int MAX_PROCESS_STATE = PROCESS_STATE_CACHED_EMPTY;
+ public static final int MAX_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
@@ -459,6 +450,9 @@
/** @hide requestType for assist context: generate full AssistStructure. */
public static final int ASSIST_CONTEXT_FULL = 1;
+ /** @hide requestType for assist context: generate full AssistStructure for auto-fill. */
+ public static final int ASSIST_CONTEXT_AUTOFILL = 2;
+
/** @hide Flag for registerUidObserver: report changes in process state. */
public static final int UID_OBSERVER_PROCSTATE = 1<<0;
@@ -835,7 +829,7 @@
/** @hide */
public int getFrontActivityScreenCompatMode() {
try {
- return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode();
+ return getService().getFrontActivityScreenCompatMode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -844,7 +838,7 @@
/** @hide */
public void setFrontActivityScreenCompatMode(int mode) {
try {
- ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode);
+ getService().setFrontActivityScreenCompatMode(mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -853,7 +847,7 @@
/** @hide */
public int getPackageScreenCompatMode(String packageName) {
try {
- return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName);
+ return getService().getPackageScreenCompatMode(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -862,7 +856,7 @@
/** @hide */
public void setPackageScreenCompatMode(String packageName, int mode) {
try {
- ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode);
+ getService().setPackageScreenCompatMode(packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -871,7 +865,7 @@
/** @hide */
public boolean getPackageAskScreenCompat(String packageName) {
try {
- return ActivityManagerNative.getDefault().getPackageAskScreenCompat(packageName);
+ return getService().getPackageAskScreenCompat(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -880,7 +874,7 @@
/** @hide */
public void setPackageAskScreenCompat(String packageName, boolean ask) {
try {
- ActivityManagerNative.getDefault().setPackageAskScreenCompat(packageName, ask);
+ getService().setPackageAskScreenCompat(packageName, ask);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1175,7 +1169,7 @@
public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) {
if (iconFilename != null) {
try {
- return ActivityManagerNative.getDefault().getTaskDescriptionIcon(iconFilename,
+ return getService().getTaskDescriptionIcon(iconFilename,
userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1564,7 +1558,7 @@
public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
throws SecurityException {
try {
- return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
+ return getService().getRecentTasks(maxNum,
flags, UserHandle.myUserId()).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1589,7 +1583,7 @@
public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)
throws SecurityException {
try {
- return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
+ return getService().getRecentTasks(maxNum,
flags, userId).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1735,7 +1729,7 @@
ArrayList<AppTask> tasks = new ArrayList<AppTask>();
List<IBinder> appTasks;
try {
- appTasks = ActivityManagerNative.getDefault().getAppTasks(mContext.getPackageName());
+ appTasks = getService().getAppTasks(mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1760,7 +1754,7 @@
private void ensureAppTaskThumbnailSizeLocked() {
if (mAppTaskThumbnailSize == null) {
try {
- mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
+ mAppTaskThumbnailSize = getService().getAppTaskThumbnailSize();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1825,7 +1819,7 @@
description = new TaskDescription();
}
try {
- return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(),
+ return getService().addAppTask(activity.getActivityToken(),
intent, description, thumbnail);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1868,7 +1862,7 @@
public List<RunningTaskInfo> getRunningTasks(int maxNum)
throws SecurityException {
try {
- return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
+ return getService().getTasks(maxNum, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1884,7 +1878,7 @@
*/
public boolean removeTask(int taskId) throws SecurityException {
try {
- return ActivityManagerNative.getDefault().removeTask(taskId);
+ return getService().removeTask(taskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2052,7 +2046,7 @@
/** @hide */
public TaskThumbnail getTaskThumbnail(int id) throws SecurityException {
try {
- return ActivityManagerNative.getDefault().getTaskThumbnail(id);
+ return getService().getTaskThumbnail(id);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2061,7 +2055,7 @@
/** @hide */
public boolean isInHomeStack(int taskId) {
try {
- return ActivityManagerNative.getDefault().isInHomeStack(taskId);
+ return getService().isInHomeStack(taskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2110,7 +2104,7 @@
*/
public void moveTaskToFront(int taskId, int flags, Bundle options) {
try {
- ActivityManagerNative.getDefault().moveTaskToFront(taskId, flags, options);
+ getService().moveTaskToFront(taskId, flags, options);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2295,7 +2289,7 @@
public List<RunningServiceInfo> getRunningServices(int maxNum)
throws SecurityException {
try {
- return ActivityManagerNative.getDefault()
+ return getService()
.getServices(maxNum, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2310,7 +2304,7 @@
public PendingIntent getRunningServiceControlPanel(ComponentName service)
throws SecurityException {
try {
- return ActivityManagerNative.getDefault()
+ return getService()
.getRunningServiceControlPanel(service);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2415,7 +2409,7 @@
*/
public void getMemoryInfo(MemoryInfo outInfo) {
try {
- ActivityManagerNative.getDefault().getMemoryInfo(outInfo);
+ getService().getMemoryInfo(outInfo);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2554,7 +2548,7 @@
*/
public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
try {
- return ActivityManagerNative.getDefault().clearApplicationUserData(packageName,
+ return getService().clearApplicationUserData(packageName,
observer, UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2588,7 +2582,7 @@
*/
public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) {
try {
- return ActivityManagerNative.getDefault().getGrantedUriPermissions(packageName,
+ return getService().getGrantedUriPermissions(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2606,7 +2600,7 @@
*/
public void clearGrantedUriPermissions(String packageName) {
try {
- ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName,
+ getService().clearGrantedUriPermissions(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2727,7 +2721,7 @@
*/
public List<ProcessErrorStateInfo> getProcessesInErrorState() {
try {
- return ActivityManagerNative.getDefault().getProcessesInErrorState();
+ return getService().getProcessesInErrorState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2890,6 +2884,29 @@
}
}
+ /** @hide */
+ public static int importanceToProcState(int importance) {
+ if (importance == IMPORTANCE_GONE) {
+ return PROCESS_STATE_NONEXISTENT;
+ } else if (importance >= IMPORTANCE_BACKGROUND) {
+ return PROCESS_STATE_HOME;
+ } else if (importance >= IMPORTANCE_SERVICE) {
+ return PROCESS_STATE_SERVICE;
+ } else if (importance > IMPORTANCE_CANT_SAVE_STATE) {
+ return PROCESS_STATE_HEAVY_WEIGHT;
+ } else if (importance >= IMPORTANCE_PERCEPTIBLE) {
+ return PROCESS_STATE_IMPORTANT_BACKGROUND;
+ } else if (importance >= IMPORTANCE_VISIBLE) {
+ return PROCESS_STATE_IMPORTANT_FOREGROUND;
+ } else if (importance >= IMPORTANCE_TOP_SLEEPING) {
+ return PROCESS_STATE_TOP_SLEEPING;
+ } else if (importance >= IMPORTANCE_FOREGROUND_SERVICE) {
+ return PROCESS_STATE_FOREGROUND_SERVICE;
+ } else {
+ return PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ }
+ }
+
/**
* The relative importance level that the system places on this
* process. May be one of {@link #IMPORTANCE_FOREGROUND},
@@ -3041,7 +3058,7 @@
*/
public List<ApplicationInfo> getRunningExternalApplications() {
try {
- return ActivityManagerNative.getDefault().getRunningExternalApplications();
+ return getService().getRunningExternalApplications();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3057,7 +3074,7 @@
*/
public boolean setProcessMemoryTrimLevel(String process, int userId, int level) {
try {
- return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId,
+ return getService().setProcessMemoryTrimLevel(process, userId,
level);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3076,7 +3093,7 @@
*/
public List<RunningAppProcessInfo> getRunningAppProcesses() {
try {
- return ActivityManagerNative.getDefault().getRunningAppProcesses();
+ return getService().getRunningAppProcesses();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3146,10 +3163,12 @@
throw new IllegalArgumentException("Listener already registered: " + listener);
}
// TODO: implement the cut point in the system process to avoid IPCs.
- UidObserver observer = new UidObserver(listener, importanceCutpoint);
+ UidObserver observer = new UidObserver(listener);
try {
getService().registerUidObserver(observer,
- UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE, mContext.getOpPackageName());
+ UID_OBSERVER_PROCSTATE | UID_OBSERVER_GONE,
+ RunningAppProcessInfo.importanceToProcState(importanceCutpoint),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3192,7 +3211,7 @@
*/
static public void getMyMemoryState(RunningAppProcessInfo outState) {
try {
- ActivityManagerNative.getDefault().getMyMemoryState(outState);
+ getService().getMyMemoryState(outState);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3211,7 +3230,7 @@
*/
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) {
try {
- return ActivityManagerNative.getDefault().getProcessMemoryInfo(pids);
+ return getService().getProcessMemoryInfo(pids);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3244,7 +3263,7 @@
*/
public void killBackgroundProcesses(String packageName) {
try {
- ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,
+ getService().killBackgroundProcesses(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3262,7 +3281,7 @@
@RequiresPermission(Manifest.permission.KILL_UID)
public void killUid(int uid, String reason) {
try {
- ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
+ getService().killUid(UserHandle.getAppId(uid),
UserHandle.getUserId(uid), reason);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3290,7 +3309,7 @@
*/
public void forceStopPackageAsUser(String packageName, int userId) {
try {
- ActivityManagerNative.getDefault().forceStopPackage(packageName, userId);
+ getService().forceStopPackage(packageName, userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3309,7 +3328,7 @@
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
try {
- return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
+ return getService().getDeviceConfigurationInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3399,7 +3418,7 @@
*/
public static boolean isUserAMonkey() {
try {
- return ActivityManagerNative.getDefault().isUserAMonkey();
+ return getService().isUserAMonkey();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3521,7 +3540,7 @@
return userId;
}
try {
- return ActivityManagerNative.getDefault().handleIncomingUser(callingPid,
+ return getService().handleIncomingUser(callingPid,
callingUid, userId, allowAll, requireFull, name, callerPackage);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3536,7 +3555,7 @@
public static int getCurrentUser() {
UserInfo ui;
try {
- ui = ActivityManagerNative.getDefault().getCurrentUser();
+ ui = getService().getCurrentUser();
return ui != null ? ui.id : 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3549,7 +3568,7 @@
*/
public boolean switchUser(int userid) {
try {
- return ActivityManagerNative.getDefault().switchUser(userid);
+ return getService().switchUser(userid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3564,8 +3583,8 @@
int currentUser = ActivityManager.getCurrentUser();
if (currentUser != UserHandle.USER_SYSTEM) {
try {
- ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM);
- ActivityManagerNative.getDefault().stopUser(currentUser, /* force= */ false, null);
+ getService().switchUser(UserHandle.USER_SYSTEM);
+ getService().stopUser(currentUser, /* force= */ false, null);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -3587,12 +3606,12 @@
* allowed to run code through scheduled alarms, receiving broadcasts,
* etc. A started user may be either the current foreground user or a
* background user; the result here does not distinguish between the two.
- * @param userid the user's id. Zero indicates the default user.
+ * @param userId the user's id. Zero indicates the default user.
* @hide
*/
public boolean isUserRunning(int userId) {
try {
- return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
+ return getService().isUserRunning(userId, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3601,7 +3620,7 @@
/** {@hide} */
public boolean isVrModePackageEnabled(ComponentName component) {
try {
- return ActivityManagerNative.getDefault().isVrModePackageEnabled(component);
+ return getService().isVrModePackageEnabled(component);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3646,6 +3665,23 @@
/**
* @hide
*/
+ public static boolean isSystemReady() {
+ if (!sSystemReady) {
+ if (ActivityThread.isSystem()) {
+ sSystemReady =
+ LocalServices.getService(ActivityManagerInternal.class).isSystemReady();
+ } else {
+ // Since this is being called from outside system server, system should be
+ // ready by now.
+ sSystemReady = true;
+ }
+ }
+ return sSystemReady;
+ }
+
+ /**
+ * @hide
+ */
public static void broadcastStickyIntent(Intent intent, int userId) {
broadcastStickyIntent(intent, AppOpsManager.OP_NONE, userId);
}
@@ -3755,7 +3791,7 @@
*/
public void setWatchHeapLimit(long pssSize) {
try {
- ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize,
+ getService().setDumpHeapDebugLimit(null, 0, pssSize,
mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3775,7 +3811,7 @@
*/
public void clearWatchHeapLimit() {
try {
- ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null);
+ getService().setDumpHeapDebugLimit(null, 0, 0, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3786,7 +3822,7 @@
*/
public void startLockTaskMode(int taskId) {
try {
- ActivityManagerNative.getDefault().startLockTaskModeById(taskId);
+ getService().startLockTaskModeById(taskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3797,7 +3833,7 @@
*/
public void stopLockTaskMode() {
try {
- ActivityManagerNative.getDefault().stopLockTaskMode();
+ getService().stopLockTaskMode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3825,7 +3861,7 @@
*/
public int getLockTaskModeState() {
try {
- return ActivityManagerNative.getDefault().getLockTaskModeState();
+ return getService().getLockTaskModeState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3843,7 +3879,7 @@
*/
public static void setVrThread(int tid) {
try {
- ActivityManagerNative.getDefault().setVrThread(tid);
+ getService().setVrThread(tid);
} catch (RemoteException e) {
// pass
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index e56fe0f..38e3572 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -194,4 +194,9 @@
* @return {@code true} if system is ready, {@code false} otherwise.
*/
public abstract boolean isSystemReady();
+
+ /**
+ * Called when the trusted state of Keyguard has changed.
+ */
+ public abstract void notifyKeyguardTrustedChanged();
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 199fda4..c09403c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,11 +16,7 @@
package android.app;
import android.content.Intent;
-import android.os.Debug;
import android.os.IBinder;
-import android.util.Log;
-
-import com.android.server.LocalServices;
/**
* {@hide}
@@ -28,8 +24,6 @@
*/
@Deprecated
public abstract class ActivityManagerNative {
- private final static String TAG = "ActivityManagerNative";
-
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
@@ -55,21 +49,9 @@
* @deprecated use ActivityManagerInternal.isSystemReady instead.
*/
static public boolean isSystemReady() {
- if (!sSystemReady) {
- if (ActivityThread.isSystem()) {
- sSystemReady =
- LocalServices.getService(ActivityManagerInternal.class).isSystemReady();
- } else {
- // Since this is being called from outside system server, system should be
- // ready by now.
- sSystemReady = true;
- }
- }
- return sSystemReady;
+ return ActivityManager.isSystemReady();
}
- static volatile boolean sSystemReady = false;
-
/**
* @deprecated use ActivityManager.broadcastStickyIntent instead.
*/
@@ -109,4 +91,4 @@
static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
ActivityManager.noteAlarmFinish(ps, sourceUid, tag);
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index d9a4690..1e7f4f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -152,6 +153,12 @@
private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
/**
+ * The display id the activity should be launched into.
+ * @hide
+ */
+ private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
+
+ /**
* The stack id the activity should be launched into.
* @hide
*/
@@ -240,6 +247,7 @@
private int mResultCode;
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
+ private int mLaunchDisplayId = INVALID_DISPLAY;
private int mLaunchStackId = INVALID_STACK_ID;
private int mLaunchTaskId = -1;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
@@ -850,6 +858,7 @@
mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
break;
}
+ mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
@@ -1015,6 +1024,25 @@
}
}
+ /**
+ * Gets the id of the display where activity should be launched.
+ * @return The id of the display where activity should be launched,
+ * {@link android.view.Display#INVALID_DISPLAY} if not set.
+ */
+ public int getLaunchDisplayId() {
+ return mLaunchDisplayId;
+ }
+
+ /**
+ * Sets the id of the display where activity should be launched.
+ * @param launchDisplayId The id of the display where the activity should be launched.
+ * @return {@code this} {@link ActivityOptions} instance.
+ */
+ public ActivityOptions setLaunchDisplayId(int launchDisplayId) {
+ mLaunchDisplayId = launchDisplayId;
+ return this;
+ }
+
/** @hide */
public int getLaunchStackId() {
return mLaunchStackId;
@@ -1209,6 +1237,7 @@
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
+ b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3e8d90b..1aa13a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -80,9 +80,16 @@
import android.os.Trace;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
+import android.provider.BlockedNumberContract;
+import android.provider.CalendarContract;
+import android.provider.CallLog;
+import android.provider.ContactsContract;
+import android.provider.Downloads;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
import android.security.net.config.NetworkSecurityConfigProvider;
+import android.service.autofill.IAutoFillCallback;
+import android.service.voice.VoiceInteractionSession;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -1793,7 +1800,7 @@
}
if (a != null) {
mNewActivities = null;
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
ActivityClientRecord prev;
do {
if (localLOGV) Slog.v(
@@ -2705,7 +2712,7 @@
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
try {
- displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
+ displayId = ActivityManager.getService().getActivityDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2785,7 +2792,7 @@
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
@@ -2815,7 +2822,7 @@
}
}
try {
- ActivityManagerNative.getDefault().reportSizeConfigurations(r.token,
+ ActivityManager.getService().reportSizeConfigurations(r.token,
horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -2876,16 +2883,24 @@
mLastAssistStructures.remove(i);
}
}
+ // Filling for auto-fill has a few differences:
+ // - it does not need an AssistContent
+ // - it does not call onProvideAssistData()
+ // - it needs an IAutoFillCallback
+ boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL;
+
Bundle data = new Bundle();
AssistStructure structure = null;
- AssistContent content = new AssistContent();
+ AssistContent content = forAutofill ? null : new AssistContent();
ActivityClientRecord r = mActivities.get(cmd.activityToken);
Uri referrer = null;
if (r != null) {
r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
- r.activity.onProvideAssistData(data);
+ if (!forAutofill) {
+ r.activity.onProvideAssistData(data);
+ }
referrer = r.activity.onProvideReferrer();
- if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL) {
+ if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) {
structure = new AssistStructure(r.activity);
Intent activityIntent = r.activity.getIntent();
if (activityIntent != null && (r.window == null ||
@@ -2895,18 +2910,28 @@
intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
intent.removeUnsafeExtras();
- content.setDefaultIntent(intent);
+ if (forAutofill) {
+ IAutoFillCallback autoFillCallback = r.activity.getAutoFillCallback();
+ data.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
+ autoFillCallback.asBinder());
+ } else {
+ content.setDefaultIntent(intent);
+ }
} else {
- content.setDefaultIntent(new Intent());
+ if (!forAutofill) {
+ content.setDefaultIntent(new Intent());
+ }
}
- r.activity.onProvideAssistContent(content);
+ if (!forAutofill) {
+ r.activity.onProvideAssistContent(content);
+ }
}
}
if (structure == null) {
structure = new AssistStructure();
}
mLastAssistStructures.add(new WeakReference<>(structure));
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
try {
mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content, referrer);
} catch (RemoteException e) {
@@ -2945,7 +2970,7 @@
}
}
try {
- ActivityManagerNative.getDefault().backgroundResourcesReleased(token);
+ ActivityManager.getService().backgroundResourcesReleased(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3044,7 +3069,7 @@
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
BroadcastReceiver receiver;
try {
@@ -3170,7 +3195,7 @@
// tell the OS that we're live now
try {
- ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);
+ ActivityManager.getService().backupAgentCreated(packageName, binder);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3227,11 +3252,11 @@
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
- ActivityManagerNative.getDefault());
+ ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(
+ ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3256,11 +3281,11 @@
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
- ActivityManagerNative.getDefault().publishService(
+ ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
- ActivityManagerNative.getDefault().serviceDoneExecuting(
+ ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
@@ -3286,10 +3311,10 @@
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
- ActivityManagerNative.getDefault().unbindFinished(
+ ActivityManager.getService().unbindFinished(
data.token, data.intent, doRebind);
} else {
- ActivityManagerNative.getDefault().serviceDoneExecuting(
+ ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
@@ -3372,7 +3397,7 @@
QueuedWork.waitToFinish();
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(
+ ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3403,7 +3428,7 @@
QueuedWork.waitToFinish();
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(
+ ActivityManager.getService().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3525,7 +3550,7 @@
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
- willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
+ willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3613,7 +3638,7 @@
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
- ActivityManagerNative.getDefault().activityResumed(token);
+ ActivityManager.getService().activityResumed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -3623,7 +3648,7 @@
// If an exception was thrown when trying to resume, then
// just end this activity.
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.finishActivity(token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
@@ -3712,7 +3737,7 @@
// Tell the activity manager we have paused.
if (!dontReport) {
try {
- ActivityManagerNative.getDefault().activityPaused(token);
+ ActivityManager.getService().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -3810,7 +3835,7 @@
// Tell activity manager we have been stopped.
try {
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
- ActivityManagerNative.getDefault().activityStopped(
+ ActivityManager.getService().activityStopped(
activity.token, state, persistentState, description);
} catch (RemoteException ex) {
if (ex instanceof TransactionTooLargeException
@@ -4065,7 +4090,7 @@
// Tell activity manager we slept.
try {
- ActivityManagerNative.getDefault().activitySlept(r.token);
+ ActivityManager.getService().activitySlept(r.token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -4319,7 +4344,7 @@
}
if (finishing) {
try {
- ActivityManagerNative.getDefault().activityDestroyed(token);
+ ActivityManager.getService().activityDestroyed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -4361,7 +4386,7 @@
// For each relaunch request, activity manager expects an answer
if (!r.onlyLocalRequest && fromServer) {
try {
- ActivityManagerNative.getDefault().activityRelaunched(token);
+ ActivityManager.getService().activityRelaunched(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4487,7 +4512,7 @@
if (r == null) {
if (!tmp.onlyLocalRequest) {
try {
- ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
+ ActivityManager.getService().activityRelaunched(tmp.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4560,7 +4585,7 @@
if (!tmp.onlyLocalRequest) {
try {
- ActivityManagerNative.getDefault().activityRelaunched(r.token);
+ ActivityManager.getService().activityRelaunched(r.token);
if (r.window != null) {
r.window.reportActivityRelaunched();
}
@@ -4925,7 +4950,7 @@
Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
}
try {
- ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
+ ActivityManager.getService().dumpHeapFinished(dhd.path);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5217,7 +5242,14 @@
}
updateDefaultDensity();
- final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
+ final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24);
+ Boolean is24Hr = null;
+ if (use24HourSetting != null) {
+ is24Hr = "24".equals(use24HourSetting) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ // null : use locale default for 12/24 hour formatting,
+ // false : use 12 hour format,
+ // true : use 24 hour format.
DateFormat.set24HourTimePref(is24Hr);
View.mDebugViewAttributes =
@@ -5269,7 +5301,7 @@
Slog.w(TAG, "Application " + data.info.getPackageName()
+ " is waiting for the debugger on port 8100...");
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
try {
mgr.showWaitingForDebugger(mAppThread, true);
} catch (RemoteException ex) {
@@ -5463,12 +5495,12 @@
}
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (mProfiler.profileFile != null && mProfiler.handlingProfiling
&& mProfiler.profileFd == null) {
Debug.stopMethodTracing();
}
- //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault()
+ //Slog.i(TAG, "am: " + ActivityManager.getService()
// + ", app thr: " + mAppThread);
try {
am.finishInstrumentation(mAppThread, resultCode, results);
@@ -5499,7 +5531,7 @@
}
try {
- ActivityManagerNative.getDefault().publishContentProviders(
+ ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -5521,7 +5553,7 @@
// be re-entrant in the case where the provider is in the same process.
ContentProviderHolder holder = null;
try {
- holder = ActivityManagerNative.getDefault().getContentProvider(
+ holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -5567,7 +5599,7 @@
+ prc.holder.info.name + ": unstableDelta="
+ unstableDelta);
}
- ActivityManagerNative.getDefault().refContentProvider(
+ ActivityManager.getService().refContentProvider(
prc.holder.connection, 1, unstableDelta);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5596,7 +5628,7 @@
Slog.v(TAG, "incProviderRef: Now unstable - "
+ prc.holder.info.name);
}
- ActivityManagerNative.getDefault().refContentProvider(
+ ActivityManager.getService().refContentProvider(
prc.holder.connection, 0, 1);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5670,7 +5702,7 @@
Slog.v(TAG, "releaseProvider: No longer stable w/lastRef="
+ lastRef + " - " + prc.holder.info.name);
}
- ActivityManagerNative.getDefault().refContentProvider(
+ ActivityManager.getService().refContentProvider(
prc.holder.connection, -1, lastRef ? 1 : 0);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5694,7 +5726,7 @@
Slog.v(TAG, "releaseProvider: No longer unstable - "
+ prc.holder.info.name);
}
- ActivityManagerNative.getDefault().refContentProvider(
+ ActivityManager.getService().refContentProvider(
prc.holder.connection, 0, -1);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5758,10 +5790,10 @@
try {
if (DEBUG_PROVIDER) {
- Slog.v(TAG, "removeProvider: Invoking ActivityManagerNative."
+ Slog.v(TAG, "removeProvider: Invoking ActivityManagerService."
+ "removeContentProvider(" + prc.holder.info.name + ")");
}
- ActivityManagerNative.getDefault().removeContentProvider(
+ ActivityManager.getService().removeContentProvider(
prc.holder.connection, false);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5795,7 +5827,7 @@
// it knows it is dead (so we don't race with its death
// notification).
try {
- ActivityManagerNative.getDefault().unstableProviderDied(
+ ActivityManager.getService().unstableProviderDied(
prc.holder.connection);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5809,7 +5841,7 @@
ProviderRefCount prc = mProviderRefCountMap.get(provider);
if (prc != null) {
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.appNotRespondingViaProvider(prc.holder.connection);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -5823,6 +5855,23 @@
final String auths[] = holder.info.authority.split(";");
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
+ if (provider != null) {
+ // If this provider is hosted by the core OS and cannot be upgraded,
+ // then I guess we're okay doing blocking calls to it.
+ for (String auth : auths) {
+ switch (auth) {
+ case ContactsContract.AUTHORITY:
+ case CallLog.AUTHORITY:
+ case CallLog.SHADOW_AUTHORITY:
+ case BlockedNumberContract.AUTHORITY:
+ case CalendarContract.AUTHORITY:
+ case Downloads.Impl.AUTHORITY:
+ case "telephony":
+ Binder.allowBlocking(provider.asBinder());
+ }
+ }
+ }
+
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
for (String auth : auths) {
@@ -5950,7 +5999,7 @@
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
- ActivityManagerNative.getDefault().removeContentProvider(
+ ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
@@ -5971,7 +6020,6 @@
retHolder = prc.holder;
}
}
-
return retHolder;
}
@@ -5988,7 +6036,7 @@
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
- final IActivityManager mgr = ActivityManagerNative.getDefault();
+ final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index ec21882..af41db0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -37,6 +37,8 @@
import android.view.Window;
import android.widget.ImageView;
+import com.android.internal.view.OneShotPreDrawListener;
+
import java.util.ArrayList;
import java.util.Collection;
@@ -570,16 +572,9 @@
protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) {
final View decorView = getDecor();
if (decorView != null) {
- decorView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- notifySharedElementEnd(snapshots);
- return true;
- }
- }
- );
+ OneShotPreDrawListener.add(decorView, () -> {
+ notifySharedElementEnd(snapshots);
+ });
}
}
@@ -816,6 +811,7 @@
if (moveWithParent && !isInTransitionGroup(parent, decor)) {
GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
parent.getViewTreeObserver().addOnPreDrawListener(listener);
+ parent.addOnAttachStateChangeListener(listener);
mGhostViewListeners.add(listener);
}
}
@@ -842,8 +838,7 @@
int numListeners = mGhostViewListeners.size();
for (int i = 0; i < numListeners; i++) {
GhostViewListeners listener = mGhostViewListeners.get(i);
- ViewGroup parent = (ViewGroup) listener.getView().getParent();
- parent.getViewTreeObserver().removeOnPreDrawListener(listener);
+ listener.removeListener();
}
mGhostViewListeners.clear();
@@ -874,15 +869,9 @@
protected void scheduleGhostVisibilityChange(final int visibility) {
final View decorView = getDecor();
if (decorView != null) {
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- setGhostVisibility(visibility);
- return true;
- }
- });
+ OneShotPreDrawListener.add(decorView, () -> {
+ setGhostVisibility(visibility);
+ });
}
}
@@ -988,16 +977,19 @@
}
}
- private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener {
+ private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener,
+ View.OnAttachStateChangeListener {
private View mView;
private ViewGroup mDecor;
private View mParent;
private Matrix mMatrix = new Matrix();
+ private ViewTreeObserver mViewTreeObserver;
public GhostViewListeners(View view, View parent, ViewGroup decor) {
mView = view;
mParent = parent;
mDecor = decor;
+ mViewTreeObserver = parent.getViewTreeObserver();
}
public View getView() {
@@ -1008,13 +1000,32 @@
public boolean onPreDraw() {
GhostView ghostView = GhostView.getGhost(mView);
if (ghostView == null) {
- mParent.getViewTreeObserver().removeOnPreDrawListener(this);
+ removeListener();
} else {
GhostView.calculateMatrix(mView, mDecor, mMatrix);
ghostView.setMatrix(mMatrix);
}
return true;
}
+
+ public void removeListener() {
+ if (mViewTreeObserver.isAlive()) {
+ mViewTreeObserver.removeOnPreDrawListener(this);
+ } else {
+ mParent.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ mParent.removeOnAttachStateChangeListener(this);
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mViewTreeObserver = v.getViewTreeObserver();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ removeListener();
+ }
}
static class SharedElementOriginalState {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 60046b5..f2616ff 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -22,9 +22,10 @@
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.Window;
+import com.android.internal.view.OneShotPreDrawListener;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -321,18 +322,12 @@
}
if (delayExitBack && decor != null) {
final ViewGroup finalDecor = decor;
- decor.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- finalDecor.getViewTreeObserver().removeOnPreDrawListener(this);
- if (mReturnExitCoordinator != null) {
- mReturnExitCoordinator.startExit(activity.mResultCode,
- activity.mResultData);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(decor, () -> {
+ if (mReturnExitCoordinator != null) {
+ mReturnExitCoordinator.startExit(activity.mResultCode,
+ activity.mResultData);
+ }
+ });
} else {
mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData);
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index cada1b8..29b83dc 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -152,7 +152,7 @@
try {
mActivityContainer = new ActivityContainerWrapper(
- ActivityManagerNative.getDefault().createVirtualActivityContainer(
+ ActivityManager.getService().createVirtualActivityContainer(
mActivity.getActivityToken(), new ActivityContainerCallback(this)));
} catch (RemoteException e) {
throw new RuntimeException("ActivityView: Unable to create ActivityContainer. "
diff --git a/core/java/android/app/AppImportanceMonitor.java b/core/java/android/app/AppImportanceMonitor.java
index e0d0d8d..b5cbeeb 100644
--- a/core/java/android/app/AppImportanceMonitor.java
+++ b/core/java/android/app/AppImportanceMonitor.java
@@ -86,7 +86,7 @@
};
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
try {
- ActivityManagerNative.getDefault().registerProcessObserver(mProcessObserver);
+ ActivityManager.getService().registerProcessObserver(mProcessObserver);
} catch (RemoteException e) {
}
List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses();
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index cf794c5..e222fee 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -349,7 +349,9 @@
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
- mAllowOptimization = Build.isAtLeastO();
+ int targetSdkVersion = manager.mHost.getContext().getApplicationInfo().targetSdkVersion;
+ // TODO: make the check N_MR1 or O
+ mAllowOptimization = targetSdkVersion > Build.VERSION_CODES.N;
}
public int getId() {
@@ -762,7 +764,7 @@
}
if (!mAllowOptimization) {
// Added fragments are added at the end to comply with prior behavior.
- mManager.moveToState(mManager.mCurState);
+ mManager.moveToState(mManager.mCurState, true);
}
}
@@ -808,7 +810,7 @@
}
}
if (!mAllowOptimization) {
- mManager.moveToState(mManager.mCurState);
+ mManager.moveToState(mManager.mCurState, true);
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f1d0e10..827e026 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -60,7 +61,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -797,7 +798,7 @@
@Override
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
try {
- ActivityManagerNative.getDefault().startActivityAsUser(
+ ActivityManager.getService().startActivityAsUser(
mMainThread.getApplicationThread(), getBasePackageName(), intent,
intent.resolveTypeIfNeeded(getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
@@ -859,7 +860,7 @@
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityIntentSender(mMainThread.getApplicationThread(), intent,
fillInIntent, resolvedType, null, null,
0, flagsMask, flagsValues, options);
@@ -878,7 +879,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
@@ -895,7 +896,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
@@ -910,7 +911,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, false, false, getUserId());
@@ -927,7 +928,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
options, false, false, getUserId());
@@ -944,7 +945,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
getUserId());
@@ -961,7 +962,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
null, true, false, getUserId());
@@ -1024,7 +1025,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions, appOp,
options, true, false, getUserId());
@@ -1038,7 +1039,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
+ ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(),
intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
@@ -1060,7 +1061,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
options, false, false, user.getIdentifier());
@@ -1077,7 +1078,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
user.getIdentifier());
@@ -1128,7 +1129,7 @@
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions,
appOp, options, true, false, user.getIdentifier());
@@ -1144,7 +1145,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
getUserId());
@@ -1180,7 +1181,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, getUserId());
@@ -1199,7 +1200,7 @@
}
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().unbroadcastIntent(
+ ActivityManager.getService().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1212,7 +1213,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
user.getIdentifier());
@@ -1227,7 +1228,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
user.getIdentifier());
@@ -1262,7 +1263,7 @@
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().broadcastIntent(
+ ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
@@ -1281,7 +1282,7 @@
}
try {
intent.prepareToLeaveProcess(this);
- ActivityManagerNative.getDefault().unbroadcastIntent(
+ ActivityManager.getService().unbroadcastIntent(
mMainThread.getApplicationThread(), intent, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1328,7 +1329,7 @@
}
}
try {
- final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
+ final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
if (intent != null) {
@@ -1347,7 +1348,7 @@
IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
getOuterContext(), receiver);
try {
- ActivityManagerNative.getDefault().unregisterReceiver(rd);
+ ActivityManager.getService().unregisterReceiver(rd);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1390,7 +1391,7 @@
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
- ComponentName cn = ActivityManagerNative.getDefault().startService(
+ ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
@@ -1419,7 +1420,7 @@
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
- int res = ActivityManagerNative.getDefault().stopService(
+ int res = ActivityManager.getService().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
if (res < 0) {
@@ -1457,8 +1458,22 @@
return bindServiceCommon(service, conn, flags, handler, user);
}
+ /** @hide */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
+ }
+
+ /** @hide */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ return mMainThread.getApplicationThread();
+ }
+
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
+ // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
@@ -1477,7 +1492,7 @@
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
- int res = ActivityManagerNative.getDefault().bindService(
+ int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
@@ -1500,7 +1515,7 @@
IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
getOuterContext(), conn);
try {
- ActivityManagerNative.getDefault().unbindService(sd);
+ ActivityManager.getService().unbindService(sd);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1516,7 +1531,7 @@
if (arguments != null) {
arguments.setAllowFds(false);
}
- return ActivityManagerNative.getDefault().startInstrumentation(
+ return ActivityManager.getService().startInstrumentation(
className, profileFile, 0, arguments, null, null, getUserId(),
null /* ABI override */);
} catch (RemoteException e) {
@@ -1541,7 +1556,7 @@
}
try {
- return ActivityManagerNative.getDefault().checkPermission(
+ return ActivityManager.getService().checkPermission(
permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1556,7 +1571,7 @@
}
try {
- return ActivityManagerNative.getDefault().checkPermissionWithToken(
+ return ActivityManager.getService().checkPermissionWithToken(
permission, pid, uid, callerToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1641,7 +1656,7 @@
@Override
public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
try {
- ActivityManagerNative.getDefault().grantUriPermission(
+ ActivityManager.getService().grantUriPermission(
mMainThread.getApplicationThread(), toPackage,
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
@@ -1652,7 +1667,7 @@
@Override
public void revokeUriPermission(Uri uri, int modeFlags) {
try {
- ActivityManagerNative.getDefault().revokeUriPermission(
+ ActivityManager.getService().revokeUriPermission(
mMainThread.getApplicationThread(),
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
@@ -1663,7 +1678,7 @@
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
try {
- return ActivityManagerNative.getDefault().checkUriPermission(
+ return ActivityManager.getService().checkUriPermission(
ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
resolveUserId(uri), null);
} catch (RemoteException e) {
@@ -1675,7 +1690,7 @@
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
try {
- return ActivityManagerNative.getDefault().checkUriPermission(
+ return ActivityManager.getService().checkUriPermission(
ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
resolveUserId(uri), callerToken);
} catch (RemoteException e) {
@@ -2141,7 +2156,8 @@
return mOuterContext;
}
- final IBinder getActivityToken() {
+ @Override
+ public IBinder getActivityToken() {
return mActivityToken;
}
@@ -2197,10 +2213,11 @@
if (!dir.exists()) {
// Failing to mkdir() may be okay, since we might not have
// enough permissions; ask vold to create on our behalf.
- final IMountService mount = IMountService.Stub.asInterface(
+ final IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
try {
- final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
+ final int res = storageManager.mkdirs(
+ getPackageName(), dir.getAbsolutePath());
if (res != 0) {
Log.w(TAG, "Failed to ensure " + dir + ": " + res);
dir = null;
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 27a0200..3464c4d 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -30,10 +30,11 @@
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.view.OneShotPreDrawListener;
+
import java.util.ArrayList;
/**
@@ -58,7 +59,7 @@
private boolean mAreViewsReady;
private boolean mIsViewsTransitionStarted;
private Transition mEnterViewsTransition;
- private OnPreDrawListener mViewsReadyListener;
+ private OneShotPreDrawListener mViewsReadyListener;
private final boolean mIsCrossTask;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
@@ -74,12 +75,17 @@
mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
final View decorView = getDecor();
if (decorView != null) {
- decorView.getViewTreeObserver().addOnPreDrawListener(
+ final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
+ viewTreeObserver.addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (mIsReadyForTransition) {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (viewTreeObserver.isAlive()) {
+ viewTreeObserver.removeOnPreDrawListener(this);
+ } else {
+ decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
}
return mIsReadyForTransition;
}
@@ -147,16 +153,10 @@
(sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) {
viewsReady(sharedElements);
} else {
- mViewsReadyListener = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- mViewsReadyListener = null;
- decor.getViewTreeObserver().removeOnPreDrawListener(this);
- viewsReady(sharedElements);
- return true;
- }
- };
- decor.getViewTreeObserver().addOnPreDrawListener(mViewsReadyListener);
+ mViewsReadyListener = OneShotPreDrawListener.add(decor, () -> {
+ mViewsReadyListener = null;
+ viewsReady(sharedElements);
+ });
decor.invalidate();
}
}
@@ -206,19 +206,13 @@
moveSharedElementsToOverlay();
mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
} else if (decorView != null) {
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- if (mResultReceiver != null) {
- Bundle state = captureSharedElementState();
- moveSharedElementsToOverlay();
- mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(decorView, () -> {
+ if (mResultReceiver != null) {
+ Bundle state = captureSharedElementState();
+ moveSharedElementsToOverlay();
+ mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
+ }
+ });
}
if (allowOverlappingTransitions()) {
startEnterTransitionOnly();
@@ -271,7 +265,7 @@
mIsReadyForTransition = true;
final ViewGroup decor = getDecor();
if (decor != null && mViewsReadyListener != null) {
- decor.getViewTreeObserver().removeOnPreDrawListener(mViewsReadyListener);
+ mViewsReadyListener.removeListener();
mViewsReadyListener = null;
}
showViews(mTransitioningViews, true);
@@ -457,20 +451,11 @@
public void onSharedElementsReady() {
final View decorView = getDecor();
if (decorView != null) {
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- startTransition(new Runnable() {
- @Override
- public void run() {
- startSharedElementTransition(sharedElementState);
- }
- });
- return false;
- }
- });
+ OneShotPreDrawListener.add(decorView, () -> {
+ startTransition(() -> {
+ startSharedElementTransition(sharedElementState);
+ });
+ });
decorView.invalidate();
}
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index b5b6e4a..6a79e6c 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -34,9 +34,10 @@
import android.transition.TransitionManager;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.Window;
+import com.android.internal.view.OneShotPreDrawListener;
+
import java.util.ArrayList;
/**
@@ -168,15 +169,9 @@
});
final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
mSharedElementNames);
- decorView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- decorView.getViewTreeObserver().removeOnPreDrawListener(this);
- setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
- return true;
- }
- });
+ OneShotPreDrawListener.add(decorView, () -> {
+ setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+ });
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
if (mListener != null) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 8124232..10ab2bc 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -414,6 +414,10 @@
// True if this fragment has been restored from previously saved state.
boolean mRestored;
+ // True if performCreateView has been called and a matching call to performDestroyView
+ // has not yet happened.
+ boolean mPerformedCreateView;
+
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
@@ -611,7 +615,7 @@
Fragment f = (Fragment)clazz.newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
- f.mArguments = args;
+ f.setArguments(args);
}
return f;
} catch (ClassNotFoundException e) {
@@ -2464,6 +2468,7 @@
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
+ mPerformedCreateView = true;
return onCreateView(inflater, container, savedInstanceState);
}
@@ -2690,6 +2695,7 @@
if (mLoaderManager != null) {
mLoaderManager.doReportNextStart();
}
+ mPerformedCreateView = false;
}
void performDestroy() {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 5a2c5e7..c7d6a48 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1072,7 +1072,7 @@
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
- if (f.mState < newState) {
+ if (f.mState <= newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
@@ -1089,65 +1089,59 @@
}
switch (f.mState) {
case Fragment.INITIALIZING:
- if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
- if (f.mSavedFragmentState != null) {
- f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
- FragmentManagerImpl.VIEW_STATE_TAG);
- f.mTarget = getFragment(f.mSavedFragmentState,
- FragmentManagerImpl.TARGET_STATE_TAG);
- if (f.mTarget != null) {
- f.mTargetRequestCode = f.mSavedFragmentState.getInt(
- FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
- }
- f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
- FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
- if (!f.mUserVisibleHint) {
- f.mDeferStart = true;
- if (newState > Fragment.STOPPED) {
- newState = Fragment.STOPPED;
+ if (newState > Fragment.INITIALIZING) {
+ if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
+ if (f.mSavedFragmentState != null) {
+ f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
+ FragmentManagerImpl.VIEW_STATE_TAG);
+ f.mTarget = getFragment(f.mSavedFragmentState,
+ FragmentManagerImpl.TARGET_STATE_TAG);
+ if (f.mTarget != null) {
+ f.mTargetRequestCode = f.mSavedFragmentState.getInt(
+ FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
+ }
+ f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
+ FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
+ if (!f.mUserVisibleHint) {
+ f.mDeferStart = true;
+ if (newState > Fragment.STOPPED) {
+ newState = Fragment.STOPPED;
+ }
}
}
- }
- f.mHost = mHost;
- f.mParentFragment = mParent;
- f.mFragmentManager = mParent != null
- ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
- dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
- f.mCalled = false;
- f.onAttach(mHost.getContext());
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onAttach()");
- }
- if (f.mParentFragment == null) {
- mHost.onAttachFragment(f);
- } else {
- f.mParentFragment.onAttachFragment(f);
- }
- dispatchOnFragmentAttached(f, mHost.getContext(), false);
-
- if (!f.mRetaining) {
- f.performCreate(f.mSavedFragmentState);
- dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
- } else {
- f.restoreChildFragmentState(f.mSavedFragmentState, true);
- f.mState = Fragment.CREATED;
- }
- f.mRetaining = false;
- if (f.mFromLayout) {
- // For fragments that are part of the content view
- // layout, we need to instantiate the view immediately
- // and the inflater will take care of adding it.
- f.mView = f.performCreateView(f.getLayoutInflater(
- f.mSavedFragmentState), null, f.mSavedFragmentState);
- if (f.mView != null) {
- f.mView.setSaveFromParentEnabled(false);
- if (f.mHidden) f.mView.setVisibility(View.GONE);
- f.onViewCreated(f.mView, f.mSavedFragmentState);
- dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
+ f.mHost = mHost;
+ f.mParentFragment = mParent;
+ f.mFragmentManager = mParent != null
+ ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
+ dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
+ f.mCalled = false;
+ f.onAttach(mHost.getContext());
+ if (!f.mCalled) {
+ throw new SuperNotCalledException("Fragment " + f
+ + " did not call through to super.onAttach()");
}
+ if (f.mParentFragment == null) {
+ mHost.onAttachFragment(f);
+ } else {
+ f.mParentFragment.onAttachFragment(f);
+ }
+ dispatchOnFragmentAttached(f, mHost.getContext(), false);
+
+ if (!f.mRetaining) {
+ f.performCreate(f.mSavedFragmentState);
+ dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
+ } else {
+ f.restoreChildFragmentState(f.mSavedFragmentState, true);
+ f.mState = Fragment.CREATED;
+ }
+ f.mRetaining = false;
}
case Fragment.CREATED:
+ // This is outside the if statement below on purpose; we want this to run
+ // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
+ // * => CREATED as part of the case fallthrough above.
+ ensureInflatedFragmentView(f);
+
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
@@ -1281,6 +1275,7 @@
}
f.mContainer = null;
f.mView = null;
+ f.mInLayout = false;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
@@ -1340,6 +1335,19 @@
moveToState(f, mCurState, 0, 0, false);
}
+ void ensureInflatedFragmentView(Fragment f) {
+ if (f.mFromLayout && !f.mPerformedCreateView) {
+ f.mView = f.performCreateView(f.getLayoutInflater(
+ f.mSavedFragmentState), null, f.mSavedFragmentState);
+ if (f.mView != null) {
+ f.mView.setSaveFromParentEnabled(false);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
+ dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
+ }
+ }
+ }
+
/**
* Fragments that have been shown or hidden don't have their visibility changed or
* animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)}
@@ -1445,11 +1453,24 @@
}
}
- void moveToState(int newState) {
+ /**
+ * Changes the state of the fragment manager to {@code newState}. If the fragment manager
+ * changes state or {@code always} is {@code true}, any fragments within it have their
+ * states updated as well.
+ *
+ * @param newState The new state for the fragment manager
+ * @param always If {@code true}, all fragments update their state, even
+ * if {@code newState} matches the current fragment manager's state.
+ */
+ void moveToState(int newState, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity");
}
+ if (!always && mCurState == newState) {
+ return;
+ }
+
mCurState = newState;
if (mActive != null) {
@@ -2024,7 +2045,7 @@
// need to run something now
FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
postponeIndex, true);
- moveToState(mCurState);
+ moveToState(mCurState, true);
}
for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
@@ -2117,7 +2138,7 @@
FragmentTransition.startTransitions(this, records, isRecordPop, 0, 1, true);
}
if (moveToState) {
- moveToState(mCurState);
+ moveToState(mCurState, true);
} else if (mActive != null) {
final int numActive = mActive.size();
for (int i = 0; i < numActive; i++) {
@@ -2691,40 +2712,40 @@
public void dispatchCreate() {
mStateSaved = false;
- moveToState(Fragment.CREATED);
+ moveToState(Fragment.CREATED, false);
}
public void dispatchActivityCreated() {
mStateSaved = false;
- moveToState(Fragment.ACTIVITY_CREATED);
+ moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchStart() {
mStateSaved = false;
- moveToState(Fragment.STARTED);
+ moveToState(Fragment.STARTED, false);
}
public void dispatchResume() {
mStateSaved = false;
- moveToState(Fragment.RESUMED);
+ moveToState(Fragment.RESUMED, false);
}
public void dispatchPause() {
- moveToState(Fragment.STARTED);
+ moveToState(Fragment.STARTED, false);
}
public void dispatchStop() {
- moveToState(Fragment.STOPPED);
+ moveToState(Fragment.STOPPED, false);
}
public void dispatchDestroyView() {
- moveToState(Fragment.CREATED);
+ moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
- moveToState(Fragment.INITIALIZING);
+ moveToState(Fragment.INITIALIZING, false);
mHost = null;
mContainer = null;
mParent = null;
@@ -3249,7 +3270,9 @@
}
// If we haven't finished entering the CREATED state ourselves yet,
- // push the inflated child fragment along.
+ // push the inflated child fragment along. This will ensureInflatedFragmentView
+ // at the right phase of the lifecycle so that we will have mView populated
+ // for compliant fragments below.
if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
moveToState(fragment, Fragment.CREATED, 0, 0, false);
} else {
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index d27dff5..088fd08 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -24,7 +24,8 @@
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
+
+import com.android.internal.view.OneShotPreDrawListener;
import java.util.ArrayList;
import java.util.Collection;
@@ -320,16 +321,9 @@
&& exitingFragment.mHidden && exitingFragment.mHiddenChanged) {
exitingFragment.setHideReplaced(true);
final View fragmentView = exitingFragment.getView();
- final ViewGroup container = exitingFragment.mContainer;
- container.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- container.getViewTreeObserver().removeOnPreDrawListener(this);
- setViewVisibility(exitingViews, View.INVISIBLE);
- return true;
- }
- });
+ OneShotPreDrawListener.add(exitingFragment.mContainer, () -> {
+ setViewVisibility(exitingViews, View.INVISIBLE);
+ });
exitTransition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
@@ -364,30 +358,22 @@
final Transition enterTransition, final ArrayList<View> enteringViews,
final Transition exitTransition, final ArrayList<View> exitingViews) {
- sceneRoot.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ OneShotPreDrawListener.add(sceneRoot, () -> {
+ if (enterTransition != null) {
+ enterTransition.removeTarget(nonExistentView);
+ ArrayList<View> views = configureEnteringExitingViews(
+ enterTransition, inFragment, sharedElementsIn, nonExistentView);
+ enteringViews.addAll(views);
+ }
- if (enterTransition != null) {
- enterTransition.removeTarget(nonExistentView);
- ArrayList<View> views = configureEnteringExitingViews(
- enterTransition, inFragment, sharedElementsIn, nonExistentView);
- enteringViews.addAll(views);
- }
-
- if (exitingViews != null) {
- ArrayList<View> tempExiting = new ArrayList<>();
- tempExiting.add(nonExistentView);
- replaceTargets(exitTransition, exitingViews, tempExiting);
- exitingViews.clear();
- exitingViews.add(nonExistentView);
- }
-
- return true;
- }
- });
+ if (exitingViews != null) {
+ ArrayList<View> tempExiting = new ArrayList<>();
+ tempExiting.add(nonExistentView);
+ replaceTargets(exitTransition, exitingViews, tempExiting);
+ exitingViews.clear();
+ exitingViews.add(nonExistentView);
+ }
+ });
}
/**
@@ -541,19 +527,13 @@
epicenterView = null;
}
- sceneRoot.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
- callSharedElementStartEnd(inFragment, outFragment, inIsPop,
- inSharedElements, false);
- if (epicenterView != null) {
- epicenterView.getBoundsOnScreen(epicenter);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(sceneRoot, () -> {
+ callSharedElementStartEnd(inFragment, outFragment, inIsPop,
+ inSharedElements, false);
+ if (epicenterView != null) {
+ epicenterView.getBoundsOnScreen(epicenter);
+ }
+ });
return sharedElementTransition;
}
@@ -643,36 +623,30 @@
TransitionSet finalSharedElementTransition = sharedElementTransition;
- sceneRoot.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
- ArrayMap<String, View> inSharedElements = captureInSharedElements(
- nameOverrides, finalSharedElementTransition, fragments);
+ OneShotPreDrawListener.add(sceneRoot, () -> {
+ ArrayMap<String, View> inSharedElements = captureInSharedElements(
+ nameOverrides, finalSharedElementTransition, fragments);
- if (inSharedElements != null) {
- sharedElementsIn.addAll(inSharedElements.values());
- sharedElementsIn.add(nonExistentView);
- }
+ if (inSharedElements != null) {
+ sharedElementsIn.addAll(inSharedElements.values());
+ sharedElementsIn.add(nonExistentView);
+ }
- callSharedElementStartEnd(inFragment, outFragment, inIsPop,
- inSharedElements, false);
- if (finalSharedElementTransition != null) {
- finalSharedElementTransition.getTargets().clear();
- finalSharedElementTransition.getTargets().addAll(sharedElementsIn);
- replaceTargets(finalSharedElementTransition, sharedElementsOut,
- sharedElementsIn);
+ callSharedElementStartEnd(inFragment, outFragment, inIsPop,
+ inSharedElements, false);
+ if (finalSharedElementTransition != null) {
+ finalSharedElementTransition.getTargets().clear();
+ finalSharedElementTransition.getTargets().addAll(sharedElementsIn);
+ replaceTargets(finalSharedElementTransition, sharedElementsOut,
+ sharedElementsIn);
- final View inEpicenterView = getInEpicenterView(inSharedElements,
- fragments, enterTransition, inIsPop);
- if (inEpicenterView != null) {
- inEpicenterView.getBoundsOnScreen(inEpicenter);
- }
- }
- return true;
- }
- });
+ final View inEpicenterView = getInEpicenterView(inSharedElements,
+ fragments, enterTransition, inIsPop);
+ if (inEpicenterView != null) {
+ inEpicenterView.getBoundsOnScreen(inEpicenter);
+ }
+ }
+ });
return sharedElementTransition;
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 92d67b7..d63d37b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -431,7 +431,8 @@
* etc.
*/
void keyguardGoingAway(int flags) = 296;
- void registerUidObserver(in IUidObserver observer, int which, String callingPackage) = 297;
+ void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
+ String callingPackage) = 297;
void unregisterUidObserver(in IUidObserver observer) = 298;
boolean isAssistDataAllowedOnCurrentActivity() = 299;
boolean showAssistFromActivity(in IBinder token, in Bundle args) = 300;
@@ -498,7 +499,7 @@
boolean supportsLocalVoiceInteraction() = 365;
void notifyPinnedStackAnimationEnded() = 366;
void removeStack(int stackId) = 367;
- void setLenientBackgroundCheck(boolean enabled) = 368;
+ void makePackageIdle(String packageName, int userId) = 368;
int getMemoryTrimLevel() = 369;
/**
* Resizes the pinned stack.
@@ -561,7 +562,11 @@
boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId) = 401;
void unregisterTaskStackListener(ITaskStackListener listener) = 402;
void moveStackToDisplay(int stackId, int displayId) = 403;
+ void enterPictureInPictureModeWithAspectRatio(in IBinder token, float aspectRatio) = 404;
+ void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio) = 405;
+ boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
+ in IBinder activityToken) = 406;
// Please keep these transaction codes the same -- they are also
// sent by C++ code. when a new method is added, use the next available transaction id.
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ee81c58..15b99c6 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -94,8 +94,8 @@
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
- void applyAdjustmentFromRankerService(in INotificationListener token, in Adjustment adjustment);
- void applyAdjustmentsFromRankerService(in INotificationListener token, in List<Adjustment> adjustments);
+ void applyAdjustmentFromAssistantService(in INotificationListener token, in Adjustment adjustment);
+ void applyAdjustmentsFromAssistantService(in INotificationListener token, in List<Adjustment> adjustments);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index cae54b6..848464c 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -53,6 +53,16 @@
int getNightMode();
/**
+ * Sets whith theme overlays to use within /vendor/overlay.
+ */
+ void setTheme(String theme);
+
+ /**
+ * Gets whith theme overlays to use within /vendor/overlay.
+ */
+ String getTheme();
+
+ /**
* Tells if UI mode is locked or not.
*/
boolean isUiModeLocked();
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index fa8d0c9..64cb9b1 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -26,7 +26,7 @@
/**
* Report that there are no longer any processes running for a uid.
*/
- void onUidGone(int uid);
+ void onUidGone(int uid, boolean disabled);
/**
* Report that a uid is now active (no longer idle).
@@ -37,5 +37,5 @@
* Report that a uid is idle -- it has either been running in the background for
* a sufficient period of time, or all of its processes have gone away.
*/
- void onUidIdle(int uid);
+ void onUidIdle(int uid, boolean disabled);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f934a9f..cc7981c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1505,7 +1505,7 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
@@ -1565,7 +1565,7 @@
intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
token, options, userId);
checkStartActivityResult(result, intents[0]);
@@ -1624,7 +1624,7 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
@@ -1684,7 +1684,7 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
@@ -1723,7 +1723,7 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 7754244..a38377e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -452,7 +452,7 @@
if (mRegisterPackage) {
try {
- ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
+ ActivityManager.getService().addPackageDependency(mPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -891,7 +891,7 @@
StrictMode.onIntentReceiverLeaked(leak);
}
try {
- ActivityManagerNative.getDefault().unregisterReceiver(
+ ActivityManager.getService().unregisterReceiver(
rd.getIIntentReceiver());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -917,7 +917,7 @@
StrictMode.onServiceConnectionLeaked(leak);
}
try {
- ActivityManagerNative.getDefault().unbindService(
+ ActivityManager.getService().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1046,7 +1046,7 @@
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
@@ -1095,7 +1095,7 @@
+ " mOrderedHint=" + ordered);
}
- final IActivityManager mgr = ActivityManagerNative.getDefault();
+ final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
@@ -1209,7 +1209,7 @@
}
if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
- IActivityManager mgr = ActivityManagerNative.getDefault();
+ IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bdb2685..261fde2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2239,7 +2239,7 @@
/**
* Returns the id of the channel this notification posts to.
*/
- public String getNotificationChannel() {
+ public String getChannel() {
return mChannelId;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cfa242b..02d5705 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -339,7 +339,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
@@ -364,7 +364,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
@@ -481,7 +481,7 @@
}
try {
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, intents, resolvedTypes, flags, options,
UserHandle.myUserId());
@@ -507,7 +507,7 @@
}
try {
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
null, null, requestCode, intents, resolvedTypes,
flags, options, user.getIdentifier());
@@ -559,7 +559,7 @@
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_BROADCAST, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
@@ -602,7 +602,7 @@
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
- ActivityManagerNative.getDefault().getIntentSender(
+ ActivityManager.getService().getIntentSender(
ActivityManager.INTENT_SENDER_SERVICE, packageName,
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
@@ -629,7 +629,7 @@
*/
public void cancel() {
try {
- ActivityManagerNative.getDefault().cancelIntentSender(mTarget);
+ ActivityManager.getService().cancelIntentSender(mTarget);
} catch (RemoteException e) {
}
}
@@ -833,7 +833,7 @@
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
- int res = ActivityManagerNative.getDefault().sendIntentSender(
+ int res = ActivityManager.getService().sendIntentSender(
mTarget, code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
@@ -853,7 +853,7 @@
@Deprecated
public String getTargetPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -882,7 +882,7 @@
@Nullable
public String getCreatorPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -910,7 +910,7 @@
*/
public int getCreatorUid() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getUidForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -941,7 +941,7 @@
@Nullable
public UserHandle getCreatorUserHandle() {
try {
- int uid = ActivityManagerNative.getDefault()
+ int uid = ActivityManager.getService()
.getUidForIntentSender(mTarget);
return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
} catch (RemoteException e) {
@@ -956,7 +956,7 @@
*/
public boolean isTargetedToPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.isIntentSenderTargetedToPackage(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -970,7 +970,7 @@
*/
public boolean isActivity() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.isIntentSenderAnActivity(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -984,7 +984,7 @@
*/
public Intent getIntent() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getIntentForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -998,7 +998,7 @@
*/
public String getTag(String prefix) {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getTagForIntentSender(mTarget, prefix);
} catch (RemoteException e) {
// Should never happen.
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 2d15beb..45831a3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -826,7 +826,8 @@
for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
ResourcesKey key = mResourceImpls.keyAt(i);
- ResourcesImpl r = mResourceImpls.valueAt(i).get();
+ WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+ ResourcesImpl r = weakImplRef != null ? weakImplRef.get() : null;
if (r != null) {
if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ r + " config to: " + config);
@@ -890,8 +891,9 @@
final int implCount = mResourceImpls.size();
for (int i = 0; i < implCount; i++) {
- final ResourcesImpl impl = mResourceImpls.valueAt(i).get();
final ResourcesKey key = mResourceImpls.keyAt(i);
+ final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+ final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
if (impl != null && key.mResDir.equals(assetPath)) {
if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
final int newLibAssetCount = 1 +
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index ee6a3ac..c529e4b 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -946,7 +946,7 @@
try {
Intent intent = new Intent(Intent.ACTION_ASSIST);
if (inclContext) {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
Bundle extras = am.getAssistContextExtras(ActivityManager.ASSIST_CONTEXT_BASIC);
if (extras != null) {
intent.replaceExtras(extras);
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index b859418..54cc4a0 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -768,7 +768,7 @@
throwIfNotConnectedLocked();
}
try {
- ActivityManagerNative.getDefault().setUserIsMonkey(enable);
+ ActivityManager.getService().setUserIsMonkey(enable);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error while setting run as monkey!", re);
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0046b0e..2e21729 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -241,6 +241,35 @@
}
/**
+ * Sets the vendor theme overlay property, then triggers a reboot.
+ * @hide
+ */
+ public void setTheme(String theme) {
+ if (mService != null) {
+ try {
+ mService.setTheme(theme);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Gets the vendor theme overlay property.
+ * @hide
+ */
+ public String getTheme() {
+ if (mService != null) {
+ try {
+ return mService.getTheme();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the currently configured night mode.
* <p>
* May be one of:
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 360087c..d89d2bb 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -285,6 +285,27 @@
= "android.app.action.NETWORK_LOGS_AVAILABLE";
/**
+ * A {@code long} containing a token of the current batch of network logs, that has to be used
+ * to retrieve the batch of logs by the device owner.
+ *
+ * @see #ACTION_NETWORK_LOGS_AVAILABLE
+ * @see DevicePolicyManager#retrieveNetworkLogs
+ * @hide
+ */
+ public static final String EXTRA_NETWORK_LOGS_TOKEN =
+ "android.app.extra.EXTRA_NETWORK_LOGS_TOKEN";
+
+ /**
+ * An {@code int} count representing a total count of network logs inside the current batch of
+ * network logs.
+ *
+ * @see #ACTION_NETWORK_LOGS_AVAILABLE
+ * @hide
+ */
+ public static final String EXTRA_NETWORK_LOGS_COUNT =
+ "android.app.extra.EXTRA_NETWORK_LOGS_COUNT";
+
+ /**
* A string containing the SHA-256 hash of the bugreport file.
*
* @see #ACTION_BUGREPORT_SHARE
@@ -336,33 +357,40 @@
public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1;
/** @hide */
- public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
+ public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS =
+ "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
/** @hide */
- public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID";
+ public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID =
+ "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID";
/** @hide */
- public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = "android.app.extra.CHOOSE_PRIVATE_KEY_URI";
+ public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI =
+ "android.app.extra.CHOOSE_PRIVATE_KEY_URI";
/** @hide */
- public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS";
+ public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS =
+ "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS";
/** @hide */
- public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
+ public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE =
+ "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
/**
* Broadcast action: notify device owner that there is a pending system update.
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE";
+ public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE =
+ "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE";
/**
* A long type extra for {@link #onSystemUpdatePending} recording the system time as given by
* {@link System#currentTimeMillis()} when the current pending system update is first available.
* @hide
*/
- public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME = "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME";
+ public static final String EXTRA_SYSTEM_UPDATE_RECEIVED_TIME =
+ "android.app.extra.SYSTEM_UPDATE_RECEIVED_TIME";
/**
* Name under which a DevicePolicy component publishes information
@@ -644,19 +672,22 @@
}
/**
- * Called when a new batch of network logs can be retrieved. This callback method will only ever
- * be called when network logging is enabled. The logs can only be retrieved while network
+ * Called each time a new batch of network logs can be retrieved. This callback method will only
+ * ever be called when network logging is enabled. The logs can only be retrieved while network
* logging is enabled.
*
* <p>This callback is only applicable to device owners.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
+ * @param batchToken The token representing the current batch of network logs.
+ * @param networkLogsCount The total count of events in the current batch of network logs.
* @see DevicePolicyManager#retrieveNetworkLogs(ComponentName)
*
* @hide
*/
- public void onNetworkLogsAvailable(Context context, Intent intent) {
+ public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
+ int networkLogsCount) {
}
/**
@@ -714,7 +745,9 @@
} else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) {
onSecurityLogsAvailable(context, intent);
} else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) {
- onNetworkLogsAvailable(context, intent);
+ long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1);
+ int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0);
+ onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 538e52b..5ca39b0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,19 +20,21 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
-import android.app.admin.NetworkEvent;
import android.app.admin.PasswordMetrics;
+import android.app.IServiceConnection;
import android.app.admin.SecurityLog.SecurityEvent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
@@ -45,10 +47,8 @@
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.ServiceManager.ServiceNotFoundException;
import android.provider.ContactsContract.Directory;
import android.provider.Settings;
import android.security.Credentials;
@@ -6649,8 +6649,6 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled whether network logging should be enabled or not.
* @throws {@link SecurityException} if {@code admin} is not a device owner.
- * @throws {@link RemoteException} if network logging could not be enabled or disabled due to
- * the logging service not being available
* @see #retrieveNetworkLogs
*
* @hide
@@ -6683,7 +6681,10 @@
}
/**
- * Called by device owner to retrieve a new batch of network logging events.
+ * Called by device owner to retrieve the most recent batch of network logging events.
+ * A device owner has to provide a batchToken provided as part of
+ * {@link DeviceAdminReceiver#onNetworkLogsAvailable} callback. If the token doesn't match the
+ * token of the most recent available batch of logs, {@code null} will be returned.
*
* <p> {@link NetworkEvent} can be one of {@link DnsEvent} or {@link ConnectEvent}.
*
@@ -6694,16 +6695,56 @@
* {@link DeviceAdminReceiver#onNetworkLogsAvailable}.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param batchToken A token of the batch to retrieve
* @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns
- * {@code null} if there's no batch currently awaiting for retrieval or if logging is disabled.
+ * {@code null} if the batch represented by batchToken is no longer available or if
+ * logging is disabled.
* @throws {@link SecurityException} if {@code admin} is not a device owner.
+ * @see DeviceAdminReceiver#onNetworkLogsAvailable
*
* @hide
*/
- public List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin) {
+ public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin,
+ long batchToken) {
throwIfParentInstance("retrieveNetworkLogs");
try {
- return mService.retrieveNetworkLogs(admin);
+ return mService.retrieveNetworkLogs(admin, batchToken);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called by device owner/ profile owner in managed profile to bind the service with each other.
+ * The service must be unexported. Note that the {@link Context} used to obtain this
+ * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used
+ * to bind to the {@link android.app.Service}.
+ * STOPSHIP (b/31952368): Update the javadoc after we policy to control which packages can talk.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param serviceIntent Identifies the service to connect to. The Intent must specify either an
+ * explicit component name or a package name to match an
+ * {@link IntentFilter} published by a service.
+ * @param conn Receives information as the service is started and stopped. This must be a
+ * valid {@link ServiceConnection} object; it must not be {@code null}.
+ * @param flags Operation options for the binding operation. See
+ * {@link Context#bindService(Intent, ServiceConnection, int)}.
+ * @param targetUser Which user to bind to.
+ * @return If you have successfully bound to the service, {@code true} is returned;
+ * {@code false} is returned if the connection is not made and you will not
+ * receive the service object.
+ * @see Context#bindService(Intent, ServiceConnection, int)
+ */
+ public boolean bindDeviceAdminServiceAsUser(
+ @NonNull ComponentName admin, Intent serviceIntent, @NonNull ServiceConnection conn,
+ @Context.BindServiceFlags int flags, @NonNull UserHandle targetUser) {
+ throwIfParentInstance("bindDeviceAdminServiceAsUser");
+ // Keep this in sync with ContextImpl.bindServiceCommon.
+ try {
+ final IServiceConnection sd = mContext.getServiceDispatcher(conn, null, flags);
+ serviceIntent.prepareToLeaveProcess(mContext);
+ return mService.bindDeviceAdminServiceAsUser(admin,
+ mContext.getIApplicationThread(), mContext.getActivityToken(), serviceIntent,
+ sd, flags, targetUser.getIdentifier());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b0aec8c..a2546c0 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,8 @@
package android.app.admin;
import android.app.admin.NetworkEvent;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.PasswordMetrics;
import android.content.ComponentName;
@@ -318,5 +320,9 @@
void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
boolean isNetworkLoggingEnabled(in ComponentName admin);
- List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin);
+ List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, long batchToken);
+
+ boolean bindDeviceAdminServiceAsUser(in ComponentName admin,
+ IApplicationThread caller, IBinder token, in Intent service,
+ IServiceConnection connection, int flags, int targetUserId);
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 6b720c0..a6f2366 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -515,6 +515,7 @@
String mIdPackage;
String mIdType;
String mIdEntry;
+ int mAutoFillId = View.NO_ID;
int mX;
int mY;
int mScrollX;
@@ -539,6 +540,7 @@
static final int FLAGS_ACTIVATED = 0x00002000;
static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
+ static final int FLAGS_HAS_AUTO_FILL_ID = 0x80000000;
static final int FLAGS_HAS_MATRIX = 0x40000000;
static final int FLAGS_HAS_ALPHA = 0x20000000;
static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -582,6 +584,9 @@
}
}
}
+ if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
+ mAutoFillId = in.readInt();
+ }
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
mY = in.readInt();
@@ -637,6 +642,9 @@
if (mId != View.NO_ID) {
flags |= FLAGS_HAS_ID;
}
+ if (mAutoFillId != View.NO_ID) {
+ flags |= FLAGS_HAS_AUTO_FILL_ID;
+ }
if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
|| (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
flags |= FLAGS_HAS_LARGE_COORDS;
@@ -681,6 +689,9 @@
}
}
}
+ if ((flags&FLAGS_HAS_AUTO_FILL_ID) != 0) {
+ out.writeInt(mAutoFillId);
+ }
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
out.writeInt(mY);
@@ -751,6 +762,16 @@
}
/**
+ * Returns the id that can be used to auto-fill the view.
+ *
+ * <p>It's only set when the {@link AssistStructure} is used for auto-filling purposes, not
+ * for assist.
+ */
+ public int getAutoFillId() {
+ return mAutoFillId;
+ }
+
+ /**
* Returns the left edge of this view, in pixels, relative to the left edge of its parent.
*/
public int getLeft() {
@@ -1322,6 +1343,11 @@
public Rect getTempRect() {
return mAssist.mTmpRect;
}
+
+ @Override
+ public void setAutoFillId(int autoFillId) {
+ mNode.mAutoFillId = autoFillId;
+ }
}
/** @hide */
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 353c640..3de159a 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioManager;
+import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -572,7 +573,7 @@
if (DBG) Log.d(TAG, "Proxy object connected");
try {
mServiceLock.writeLock().lock();
- mService = IBluetoothA2dp.Stub.asInterface(service);
+ mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
} finally {
mServiceLock.writeLock().unlock();
}
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 74302f2..9dfc4b4 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -481,7 +482,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothA2dpSink.Stub.asInterface(service);
+ mService = IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bb344a6..b0e27a4 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -604,10 +604,6 @@
*/
public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
if (!getLeAccess()) return null;
- if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
- Log.e(TAG, "Bluetooth LE advertising not supported");
- return null;
- }
synchronized(mLock) {
if (sBluetoothLeAdvertiser == null) {
sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
@@ -1357,24 +1353,6 @@
}
/**
- * Returns whether peripheral mode is supported.
- *
- * @hide
- */
- public boolean isPeripheralModeSupported() {
- if (getState() != STATE_ON) return false;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.isPeripheralModeSupported();
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get peripheral mode capability: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
* Return true if offloaded filters are supported
*
* @return true if chipset supports on-chip filtering
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index a395aa4..0261b1b 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -22,6 +22,7 @@
import android.content.ServiceConnection;
import android.media.MediaMetadata;
import android.media.session.PlaybackState;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -284,7 +285,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothAvrcpController.Stub.asInterface(service);
+ mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index f46a3b3..28421eb 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -20,6 +20,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -1037,7 +1038,7 @@
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothHeadset.Stub.asInterface(service);
+ mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service));
mHandler.sendMessage(mHandler.obtainMessage(
MESSAGE_HEADSET_SERVICE_CONNECTED));
}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 93790fe..c7c64c4 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -1122,7 +1123,7 @@
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothHeadsetClient.Stub.asInterface(service);
+ mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 4949c24..8d77888 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -522,7 +523,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothHealth.Stub.asInterface(service);
+ mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 252e3d2..e3288f3 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -479,7 +480,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothInputDevice.Stub.asInterface(service);
+ mService = IBluetoothInputDevice.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this);
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 7f57acf..2e73051 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -371,7 +371,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) log("Proxy object connected");
- mService = IBluetoothMap.Stub.asInterface(service);
+ mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 744f942..2a026a9 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -368,7 +369,7 @@
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
- mPanService = IBluetoothPan.Stub.asInterface(service);
+ mPanService = IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.PAN,
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index eab4c6f..9f00e1a 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.RemoteException;
+import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
@@ -288,7 +289,7 @@
if (DBG) {
log("Proxy object connected");
}
- mService = IBluetoothPbapClient.Stub.asInterface(service);
+ mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient.this);
}
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index e70c936..89c1bf8 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.RemoteException;
+import android.os.Binder;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
@@ -393,7 +394,7 @@
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) log("Proxy object connected");
- mService = IBluetoothSap.Stub.asInterface(service);
+ mService = IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this);
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 96a1ae8..7c5458b 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -100,7 +100,6 @@
boolean factoryReset();
boolean isMultiAdvertisementSupported();
- boolean isPeripheralModeSupported();
boolean isOffloadedFilteringSupported();
boolean isOffloadedScanBatchingSupported();
boolean isActivityAndEnergyReportingSupported();
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 6ad442b..dde0ac6 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -54,7 +54,7 @@
boolean getAudioRouteAllowed();
boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device);
boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device);
- void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
+ oneway void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type);
void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type);
boolean enableWBS();
diff --git a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
index 96c59e2..541583f 100755
--- a/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
+++ b/core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl
@@ -24,7 +24,7 @@
*
* {@hide}
*/
-interface IBluetoothProfileServiceConnection {
+oneway interface IBluetoothProfileServiceConnection {
void onServiceConnected(in ComponentName comp, in IBinder service);
void onServiceDisconnected(in ComponentName comp);
}
diff --git a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
index feccdce..0da4e88 100644
--- a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -21,7 +21,7 @@
*
* {@hide}
*/
-interface IBluetoothStateChangeCallback
+oneway interface IBluetoothStateChangeCallback
{
void onBluetoothStateChange(boolean on);
}
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index f53ca94..9e87230 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -30,10 +30,24 @@
* @hide
*/
public class OobData implements Parcelable {
+ private byte[] leBluetoothDeviceAddress;
private byte[] securityManagerTk;
private byte[] leSecureConnectionsConfirmation;
private byte[] leSecureConnectionsRandom;
+ public byte[] getLeBluetoothDeviceAddress() {
+ return leBluetoothDeviceAddress;
+ }
+
+ /**
+ * Sets the LE Bluetooth Device Address value to be used during LE pairing.
+ * The value shall be 7 bytes. Please see Bluetooth CSSv6, Part A 1.16 for
+ * a detailed description.
+ */
+ public void setLeBluetoothDeviceAddress(byte[] leBluetoothDeviceAddress) {
+ this.leBluetoothDeviceAddress = leBluetoothDeviceAddress;
+ }
+
public byte[] getSecurityManagerTk() {
return securityManagerTk;
}
@@ -66,6 +80,7 @@
public OobData() { }
private OobData(Parcel in) {
+ leBluetoothDeviceAddress = in.createByteArray();
securityManagerTk = in.createByteArray();
leSecureConnectionsConfirmation = in.createByteArray();
leSecureConnectionsRandom = in.createByteArray();
@@ -77,6 +92,7 @@
@Override
public void writeToParcel(Parcel out, int flags) {
+ out.writeByteArray(leBluetoothDeviceAddress);
out.writeByteArray(securityManagerTk);
out.writeByteArray(leSecureConnectionsConfirmation);
out.writeByteArray(leSecureConnectionsRandom);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 26f2dea..5d27662 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -111,12 +111,6 @@
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
- if (!mBluetoothAdapter.isMultipleAdvertisementSupported() &&
- !mBluetoothAdapter.isPeripheralModeSupported()) {
- postStartFailure(callback,
- AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED);
- return;
- }
boolean isConnectable = settings.isConnectable();
if (totalBytes(advertiseData, isConnectable) > MAX_ADVERTISING_DATA_BYTES ||
totalBytes(scanResponse, false) > MAX_ADVERTISING_DATA_BYTES) {
@@ -236,9 +230,9 @@
private final AdvertiseSettings mSettings;
private final IBluetoothGatt mBluetoothGatt;
- // mAdvertiserId 0: not registered
- // -1: advertise stopped or registration timeout
- // >0: registered and advertising started
+ // mAdvertiserId -1: not registered
+ // -2: advertise stopped or registration timeout
+ // >=0: registered and advertising started
private int mAdvertiserId;
private boolean mIsAdvertising = false;
@@ -251,12 +245,12 @@
mScanResponse = scanResponse;
mSettings = settings;
mBluetoothGatt = bluetoothGatt;
- mAdvertiserId = 0;
+ mAdvertiserId = -1;
}
public void startRegisteration() {
synchronized (this) {
- if (mAdvertiserId == -1) return;
+ if (mAdvertiserId == -2) return;
try {
mBluetoothGatt.registerAdvertiser(this);
@@ -264,13 +258,13 @@
} catch (InterruptedException | RemoteException e) {
Log.e(TAG, "Failed to start registeration", e);
}
- if (mAdvertiserId > 0 && mIsAdvertising) {
+ if (mAdvertiserId >= 0 && mIsAdvertising) {
mLeAdvertisers.put(mAdvertiseCallback, this);
- } else if (mAdvertiserId <= 0) {
+ } else if (mAdvertiserId < 0) {
// Registration timeout, reset mClientIf to -1 so no subsequent operations can
// proceed.
- if (mAdvertiserId == 0) mAdvertiserId = -1;
+ if (mAdvertiserId == 0) mAdvertiserId = -2;
// Post internal error if registration failed.
postStartFailure(mAdvertiseCallback,
AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
@@ -278,7 +272,7 @@
// Unregister application if it's already registered but advertise failed.
try {
mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -1;
+ mAdvertiserId = -2;
} catch (RemoteException e) {
Log.e(TAG, "remote exception when unregistering", e);
}
@@ -312,7 +306,7 @@
synchronized (this) {
if (status == BluetoothGatt.GATT_SUCCESS) {
try {
- if (mAdvertiserId == -1) {
+ if (mAdvertiserId == -2) {
// Registration succeeds after timeout, unregister advertiser.
mBluetoothGatt.unregisterAdvertiser(advertiserId);
} else {
@@ -326,7 +320,7 @@
}
}
// Registration failed.
- mAdvertiserId = -1;
+ mAdvertiserId = -2;
notifyAll();
}
}
@@ -348,7 +342,7 @@
// unregister advertiser for stop.
try {
mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -1;
+ mAdvertiserId = -2;
mIsAdvertising = false;
mLeAdvertisers.remove(mAdvertiseCallback);
} catch (RemoteException e) {
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 10e6fb2..231dace 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -16,7 +16,7 @@
package android.content;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
import android.app.QueuedWork;
@@ -366,7 +366,7 @@
*/
public final void finish() {
if (mType == TYPE_COMPONENT) {
- final IActivityManager mgr = ActivityManagerNative.getDefault();
+ final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
// If this is a broadcast component, we need to make sure any
// queued work is complete before telling AM we are done, so
@@ -393,7 +393,7 @@
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
- final IActivityManager mgr = ActivityManagerNative.getDefault();
+ final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);
}
}
@@ -519,7 +519,7 @@
* Context#startService(Intent)} for more information.
*/
public IBinder peekService(Context myContext, Intent service) {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
IBinder binder = null;
try {
service.prepareToLeaveProcess(myContext);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 1e6424e..f369409 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -42,6 +42,7 @@
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -463,6 +464,23 @@
}
}
+ @Override
+ public boolean refresh(String callingPkg, Uri uri, Bundle args,
+ ICancellationSignal cancellationSignal) throws RemoteException {
+ validateIncomingUri(uri);
+ uri = getUriWithoutUserId(uri);
+ if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.refresh(uri, args,
+ CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
+ }
+
private void enforceFilePermission(String callingPkg, Uri uri, String mode,
IBinder callerToken) throws FileNotFoundException, SecurityException {
if (mode != null && mode.indexOf('w') != -1) {
@@ -1093,6 +1111,33 @@
}
/**
+ * Implement this to support refresh of content identified by {@code uri}. By default, this
+ * method returns false; providers who wish to implement this should return true to signal the
+ * client that the provider has tried refreshing with its own implementation.
+ * <p>
+ * This allows clients to request an explicit refresh of content identified by {@code uri}.
+ * <p>
+ * Client code should only invoke this method when there is a strong indication (such as a user
+ * initiated pull to refresh gesture) that the content is stale.
+ * <p>
+ * Remember to send {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
+ * notifications when content changes.
+ *
+ * @param uri The Uri identifying the data to refresh.
+ * @param args Additional options from the client. The definitions of these are specific to the
+ * content provider being called.
+ * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
+ * none. For example, if you called refresh on a particular uri, you should call
+ * {@link CancellationSignal#throwIfCanceled()} to check whether the client has
+ * canceled the refresh request.
+ * @return true if the provider actually tried refreshing.
+ */
+ public boolean refresh(Uri uri, @Nullable Bundle args,
+ @Nullable CancellationSignal cancellationSignal) {
+ return false;
+ }
+
+ /**
* @hide
* Implementation when a caller has performed an insert on the content
* provider, but that call has been rejected for the operation given
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 9221fbb..fd6cddb 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -147,13 +147,7 @@
if (cursor == null) {
return null;
}
-
- if ("com.google.android.gms".equals(mPackageName)) {
- // They're casting to a concrete subclass, sigh
- return cursor;
- } else {
- return new CursorWrapperInner(cursor);
- }
+ return new CursorWrapperInner(cursor);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -234,6 +228,30 @@
}
}
+ /** @hide */
+ public boolean refresh(Uri url, @Nullable Bundle args,
+ @Nullable CancellationSignal cancellationSignal) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
+ beforeRemote();
+ try {
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ remoteCancellationSignal = mContentProvider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
+ }
+ return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ } finally {
+ afterRemote();
+ }
+ }
+
/** See {@link ContentProvider#insert ContentProvider.insert} */
public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
throws RemoteException {
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 4769bd0..eadc013db 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -355,6 +355,20 @@
Uri.writeToParcel(reply, out);
return true;
}
+
+ case REFRESH_TRANSACTION: {
+ data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
+ Uri url = Uri.CREATOR.createFromParcel(data);
+ Bundle args = data.readBundle();
+ ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
+ data.readStrongBinder());
+
+ boolean out = refresh(callingPkg, url, args, signal);
+ reply.writeNoException();
+ reply.writeInt(out ? 0 : -1);
+ return true;
+ }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -422,6 +436,7 @@
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
+ Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
adaptor.initialize(d);
} else {
adaptor.close();
@@ -760,5 +775,28 @@
}
}
+ public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ data.writeString(callingPkg);
+ url.writeToParcel(data, 0);
+ data.writeBundle(args);
+ data.writeStrongBinder(signal != null ? signal.asBinder() : null);
+
+ mRemote.transact(IContentProvider.REFRESH_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ int success = reply.readInt();
+ return (success == 0);
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index daa1b93..54dcd0a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -23,7 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -194,6 +194,15 @@
public static final String EXTRA_SIZE = "android.content.extra.SIZE";
/**
+ * An extra boolean describing whether a particular provider supports refresh
+ * or not. If a provider supports refresh, it should include this key in its
+ * returned Cursor as part of its query call.
+ *
+ * @hide
+ */
+ public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
+
+ /**
* This is the Android platform's base MIME type for a content: URI
* containing a Cursor of a single item. Applications should use this
* as the base type along with their own sub-type of their content: URIs
@@ -388,7 +397,7 @@
}
try {
- String type = ActivityManagerNative.getDefault().getProviderMimeType(
+ String type = ActivityManager.getService().getProviderMimeType(
ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
return type;
} catch (RemoteException e) {
@@ -664,6 +673,47 @@
}
/**
+ * This allows clients to request an explicit refresh of content identified by {@code uri}.
+ * <p>
+ * Client code should only invoke this method when there is a strong indication (such as a user
+ * initiated pull to refresh gesture) that the content is stale.
+ * <p>
+ *
+ * @param url The Uri identifying the data to refresh.
+ * @param args Additional options from the client. The definitions of these are specific to the
+ * content provider being called.
+ * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
+ * none. For example, if you called refresh on a particular uri, you should call
+ * {@link CancellationSignal#throwIfCanceled()} to check whether the client has
+ * canceled the refresh request.
+ * @return true if the provider actually tried refreshing.
+ */
+ public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
+ @Nullable CancellationSignal cancellationSignal) {
+ Preconditions.checkNotNull(url, "url");
+ IContentProvider provider = acquireProvider(url);
+ if (provider == null) {
+ return false;
+ }
+
+ try {
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ remoteCancellationSignal = provider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
+ }
+ return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return false;
+ } finally {
+ releaseProvider(provider);
+ }
+ }
+
+ /**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
*
@@ -1792,7 +1842,7 @@
@Intent.AccessUriMode int modeFlags) {
Preconditions.checkNotNull(uri, "uri");
try {
- ActivityManagerNative.getDefault().takePersistableUriPermission(
+ ActivityManager.getService().takePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
@@ -1810,7 +1860,7 @@
@Intent.AccessUriMode int modeFlags) {
Preconditions.checkNotNull(uri, "uri");
try {
- ActivityManagerNative.getDefault().releasePersistableUriPermission(
+ ActivityManager.getService().releasePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
@@ -1828,7 +1878,7 @@
*/
public @NonNull List<UriPermission> getPersistedUriPermissions() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPersistedUriPermissions(mPackageName, true).getList();
} catch (RemoteException e) {
throw new RuntimeException("Activity manager has died", e);
@@ -1844,7 +1894,7 @@
*/
public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPersistedUriPermissions(mPackageName, false).getList();
} catch (RemoteException e) {
throw new RuntimeException("Activity manager has died", e);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 322cc7b..5fa4275 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -32,6 +32,10 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.LoadedApk;
+import android.app.admin.DevicePolicyManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -2333,7 +2337,7 @@
* matches <var>filter</var>, in the main application thread.
*
* <p>The system may broadcast Intents that are "sticky" -- these stay
- * around after the broadcast as finished, to be sent to any later
+ * around after the broadcast has finished, to be sent to any later
* registrations. If your IntentFilter matches one of these sticky
* Intents, that Intent will be returned by this function
* <strong>and</strong> sent to your <var>receiver</var> as if it had just
@@ -3338,6 +3342,14 @@
public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
/**
+ * Official published name of the (internal) auto-fill service.
+ *
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String AUTO_FILL_MANAGER_SERVICE = "autofill";
+
+ /**
* Use with {@link #getSystemService} to access the
* {@link com.android.server.voiceinteraction.SoundTriggerService}.
*
@@ -4355,4 +4367,27 @@
public boolean isCredentialEncryptedStorage() {
return isCredentialProtectedStorage();
}
+
+ /**
+ * @hide
+ */
+ public IBinder getActivityToken() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
+ * @hide
+ */
+ public IApplicationThread getIApplicationThread() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index edc8d82..7533655 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,7 +16,10 @@
package android.content;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -857,4 +860,29 @@
public boolean isCredentialProtectedStorage() {
return mBase.isCredentialProtectedStorage();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public IBinder getActivityToken() {
+ return mBase.getActivityToken();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ return mBase.getServiceDispatcher(conn, handler, flags);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ return mBase.getIApplicationThread();
+ }
}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 4afe38b..ee8a22f 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -65,6 +65,9 @@
public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
+ public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args,
+ ICancellationSignal cancellationSignal) throws RemoteException;
+
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
@@ -88,4 +91,5 @@
static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
+ static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
}
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 32ca6c2..4adb5b7 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -16,7 +16,7 @@
package android.content;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.Handler;
@@ -187,7 +187,7 @@
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
- int res = ActivityManagerNative.getDefault().sendIntentSender(mTarget,
+ int res = ActivityManager.getService().sendIntentSender(mTarget,
code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
@@ -207,7 +207,7 @@
@Deprecated
public String getTargetPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -226,7 +226,7 @@
*/
public String getCreatorPackage() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getPackageForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -245,7 +245,7 @@
*/
public int getCreatorUid() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getUidForIntentSender(mTarget);
} catch (RemoteException e) {
// Should never happen.
@@ -266,7 +266,7 @@
*/
public UserHandle getCreatorUserHandle() {
try {
- int uid = ActivityManagerNative.getDefault()
+ int uid = ActivityManager.getService()
.getUidForIntentSender(mTarget);
return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
} catch (RemoteException e) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 74ec8e4..9b99bbf 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -489,6 +489,13 @@
public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;
/**
+ * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
+ * and for most purposes is considered as not installed.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 7;
+
+ /**
* When set, at least one component inside this application is direct boot
* aware.
*
@@ -496,12 +503,6 @@
*/
public static final int PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE = 1 << 8;
- /**
- * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
- * and for most purposes is considered as not installed.
- * {@hide}
- */
- public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9;
/**
* When set, signals that the application is required for the system user and should not be
@@ -509,7 +510,7 @@
*
* @hide
*/
- public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10;
+ public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 9;
/**
* When set, the application explicitly requested that its activities by resizeable by default.
@@ -517,7 +518,7 @@
*
* @hide
*/
- public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET = 1 << 11;
+ public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET = 1 << 10;
/**
* The application isn't requesting explicitly requesting for its activities to be resizeable or
@@ -531,7 +532,7 @@
*
* @hide
*/
- public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION = 1 << 12;
+ public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION = 1 << 11;
/**
* Value for {@link #privateFlags}: {@code true} means the OS should go ahead and
@@ -539,7 +540,7 @@
* foreground-equivalent run state. Defaults to {@code false} if unspecified.
* @hide
*/
- public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 13;
+ public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
/**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
@@ -1219,5 +1220,5 @@
/** {@hide} */ public String[] getSplitCodePaths() { return splitSourceDirs; }
/** {@hide} */ public String getResourcePath() { return scanPublicSourceDir; }
/** {@hide} */ public String getBaseResourcePath() { return publicSourceDir; }
- /** {@hide} */ public String[] getSplitResourcePaths() { return splitSourceDirs; }
+ /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; }
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 11f0eb6..d753a6e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -492,7 +492,7 @@
/**
* Update status of external media on the package manager to scan and
* install packages installed on the external media. Like say the
- * MountService uses this to call into the package manager to update
+ * StorageManagerService uses this to call into the package manager to update
* status of sdcard.
*/
void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6b4fea6..ad0a6b2 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -163,6 +163,12 @@
public abstract boolean isPackageDataProtected(int userId, String packageName);
/**
+ * Returns {@code true} if a given package is installed as ephemeral. Otherwise, returns
+ * {@code false}.
+ */
+ public abstract boolean isPackageEphemeral(int userId, String packageName);
+
+ /**
* Gets whether the package was ever launched.
* @param packageName The package name.
* @param userId The user for which to check.
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index a93870e..f7c4d59 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -193,7 +193,11 @@
* The following list includes descriptions for the different attributes within a static shortcut:
* <dl>
* <dt>{@code android:shortcutId}</dt>
- * <dd>Mandatory shortcut ID</dd>
+ * <dd>Mandatory shortcut ID.
+ * <p>
+ * This must be a string literal.
+ * A resource string, such as <code>@string/foo</code>, cannot be used.
+ * </dd>
*
* <dt>{@code android:enabled}</dt>
* <dd>Default is {@code true}. Can be set to {@code false} in order
@@ -206,15 +210,24 @@
*
* <dt>{@code android:shortcutShortLabel}</dt>
* <dd>Mandatory shortcut short label.
- * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.</dd>
+ * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.
+ * <p>
+ * This must be a resource string, such as <code>@string/shortcut_label</code>.
+ * </dd>
*
* <dt>{@code android:shortcutLongLabel}</dt>
* <dd>Shortcut long label.
- * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.</dd>
+ * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.
+ * <p>
+ * This must be a resource string, such as <code>@string/shortcut_long_label</code>.
+ * </dd>
*
* <dt>{@code android:shortcutDisabledMessage}</dt>
* <dd>When {@code android:enabled} is set to
- * {@code false}, this attribute is used to display a custom disabled message.</dd>
+ * {@code false}, this attribute is used to display a custom disabled message.
+ * <p>
+ * This must be a resource string, such as <code>@string/shortcut_disabled_message</code>.
+ * </dd>
*
* <dt>{@code intent}</dt>
* <dd>Intent to launch when the user selects the shortcut.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index f17fd55..cdf7013 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.Binder;
import android.os.CancellationSignal;
@@ -892,7 +892,7 @@
private int getCurrentUserId() {
try {
- return ActivityManagerNative.getDefault().getCurrentUser().id;
+ return ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
index d2c3d755..3fe645c 100644
--- a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
+++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl
@@ -25,7 +25,7 @@
*
* @hide
*/
-interface IActivityRecognitionHardwareClient {
+oneway interface IActivityRecognitionHardwareClient {
/**
* Hardware Activity-Recognition availability event.
*
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
index c99cb0c..a7dd035 100644
--- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -24,7 +24,7 @@
*
* @hide
*/
-interface IFusedLocationHardwareSink {
+oneway interface IFusedLocationHardwareSink {
/**
* Event generated when a batch of location information is available.
*
@@ -50,4 +50,4 @@
* changes (location is successful/unsuccessful).
*/
void onStatusChanged(int status) = 3;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index a5b4eb5..e0a026e 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -38,9 +38,15 @@
public static final int PROVISIONING_OK = 1;
public static final int PROVISIONING_FAIL = 2;
public static final int COMPLETE_LIFECYCLE = 3;
+ /** @hide */ public static final int ERROR_STARTING_IPV4 = 4;
+ /** @hide */ public static final int ERROR_STARTING_IPV6 = 5;
+ /** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
/** {@hide} */
- @IntDef(value = {PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE})
+ @IntDef(value = {
+ PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
+ ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@@ -95,6 +101,7 @@
final static class Decoder {
static final SparseArray<String> constants = MessageUtils.findMessageNames(
- new Class[]{IpManagerEvent.class}, new String[]{"PROVISIONING_", "COMPLETE_"});
+ new Class[]{IpManagerEvent.class},
+ new String[]{"PROVISIONING_", "COMPLETE_", "ERROR_"});
}
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 252385f..263750a 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.hardware.health.V1_0.Constants;
import com.android.internal.app.IBatteryStats;
/**
@@ -118,20 +119,20 @@
public static final String EXTRA_CHARGE_COUNTER = "charge_counter";
// values for "status" field in the ACTION_BATTERY_CHANGED Intent
- public static final int BATTERY_STATUS_UNKNOWN = 1;
- public static final int BATTERY_STATUS_CHARGING = 2;
- public static final int BATTERY_STATUS_DISCHARGING = 3;
- public static final int BATTERY_STATUS_NOT_CHARGING = 4;
- public static final int BATTERY_STATUS_FULL = 5;
+ public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
+ public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
+ public static final int BATTERY_STATUS_DISCHARGING = Constants.BATTERY_STATUS_DISCHARGING;
+ public static final int BATTERY_STATUS_NOT_CHARGING = Constants.BATTERY_STATUS_NOT_CHARGING;
+ public static final int BATTERY_STATUS_FULL = Constants.BATTERY_STATUS_FULL;
// values for "health" field in the ACTION_BATTERY_CHANGED Intent
- public static final int BATTERY_HEALTH_UNKNOWN = 1;
- public static final int BATTERY_HEALTH_GOOD = 2;
- public static final int BATTERY_HEALTH_OVERHEAT = 3;
- public static final int BATTERY_HEALTH_DEAD = 4;
- public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
- public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
- public static final int BATTERY_HEALTH_COLD = 7;
+ public static final int BATTERY_HEALTH_UNKNOWN = Constants.BATTERY_HEALTH_UNKNOWN;
+ public static final int BATTERY_HEALTH_GOOD = Constants.BATTERY_HEALTH_GOOD;
+ public static final int BATTERY_HEALTH_OVERHEAT = Constants.BATTERY_HEALTH_OVERHEAT;
+ public static final int BATTERY_HEALTH_DEAD = Constants.BATTERY_HEALTH_DEAD;
+ public static final int BATTERY_HEALTH_OVER_VOLTAGE = Constants.BATTERY_HEALTH_OVER_VOLTAGE;
+ public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = Constants.BATTERY_HEALTH_UNSPECIFIED_FAILURE;
+ public static final int BATTERY_HEALTH_COLD = Constants.BATTERY_HEALTH_COLD;
// values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
// These must be powers of 2.
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7b7533b..0136979 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -75,36 +75,35 @@
/**
* Control whether dump() calls are allowed.
*/
- private static String sDumpDisabled = null;
+ private static volatile String sDumpDisabled = null;
/**
* Global transaction tracker instance for this process.
*/
- private static TransactionTracker sTransactionTracker = null;
+ private static volatile TransactionTracker sTransactionTracker = null;
// Transaction tracking code.
/**
* Flag indicating whether we should be tracing transact calls.
- *
*/
- private static boolean sTracingEnabled = false;
+ private static volatile boolean sTracingEnabled = false;
/**
* Enable Binder IPC tracing.
*
* @hide
*/
- public static void enableTracing() {
+ public static void enableTracing() {
sTracingEnabled = true;
- };
+ }
/**
* Disable Binder IPC tracing.
*
* @hide
*/
- public static void disableTracing() {
+ public static void disableTracing() {
sTracingEnabled = false;
}
@@ -128,6 +127,59 @@
return sTransactionTracker;
}
+ /** {@hide} */
+ static volatile boolean sWarnOnBlocking = false;
+
+ /**
+ * Warn if any blocking binder transactions are made out from this process.
+ * This is typically only useful for the system process, to prevent it from
+ * blocking on calls to external untrusted code. Instead, all outgoing calls
+ * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls
+ * which deliver results through a callback interface.
+ *
+ * @hide
+ */
+ public static void setWarnOnBlocking(boolean warnOnBlocking) {
+ sWarnOnBlocking = warnOnBlocking;
+ }
+
+ /**
+ * Allow blocking calls on the given interface, overriding the requested
+ * value of {@link #setWarnOnBlocking(boolean)}.
+ * <p>
+ * This should only be rarely called when you are <em>absolutely sure</em>
+ * the remote interface is a built-in system component that can never be
+ * upgraded. In particular, this <em>must never</em> be called for
+ * interfaces hosted by package that could be upgraded or replaced,
+ * otherwise you risk system instability if that remote interface wedges.
+ *
+ * @hide
+ */
+ public static IBinder allowBlocking(IBinder binder) {
+ try {
+ if (binder instanceof BinderProxy) {
+ ((BinderProxy) binder).mWarnOnBlocking = false;
+ } else if (binder != null
+ && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
+ Log.w(TAG, "Unable to allow blocking on interface " + binder);
+ }
+ } catch (RemoteException ignored) {
+ }
+ return binder;
+ }
+
+ /**
+ * Inherit the current {@link #allowBlocking(IBinder)} value from one given
+ * interface to another.
+ *
+ * @hide
+ */
+ public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) {
+ if (fromBinder instanceof BinderProxy && toBinder instanceof BinderProxy) {
+ ((BinderProxy) toBinder).mWarnOnBlocking = ((BinderProxy) fromBinder).mWarnOnBlocking;
+ }
+ }
+
/* mObject is used by native code, do not remove or rename */
private long mObject;
private IInterface mOwner;
@@ -322,9 +374,7 @@
* re-enabled.
*/
public static void setDumpDisabled(String msg) {
- synchronized (Binder.class) {
- sDumpDisabled = msg;
- }
+ sDumpDisabled = msg;
}
/**
@@ -400,10 +450,7 @@
}
void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final String disabled;
- synchronized (Binder.class) {
- disabled = sDumpDisabled;
- }
+ final String disabled = sDumpDisabled;
if (disabled == null) {
try {
dump(fd, pw, args);
@@ -612,6 +659,9 @@
}
final class BinderProxy implements IBinder {
+ // Assume the process-wide default value when created
+ volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking;
+
public native boolean pingBinder();
public native boolean isBinderAlive();
@@ -621,6 +671,15 @@
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
+
+ if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
+ // For now, avoid spamming the log by disabling after we've logged
+ // about this interface at least once
+ mWarnOnBlocking = false;
+ Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+ new Throwable());
+ }
+
final boolean tracingEnabled = Binder.isTracingEnabled();
if (tracingEnabled) {
final Throwable tr = new Throwable();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index e5832c8..0d6d369 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -924,16 +924,4 @@
return -1;
}
}
-
- /**
- * Check if the device is running on the Android O release or newer.
- *
- * @return {@code true} if O APIs are available for use
- *
- * @hide
- */
- public static boolean isAtLeastO() {
- return !"REL".equals(VERSION.CODENAME)
- && "O".compareTo(VERSION.CODENAME) <= 0;
- }
}
diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java
index 58acbcf..c7bf0fd 100644
--- a/core/java/android/os/CountDownTimer.java
+++ b/core/java/android/os/CountDownTimer.java
@@ -125,19 +125,28 @@
if (millisLeft <= 0) {
onFinish();
- } else if (millisLeft < mCountdownInterval) {
- // no tick, just delay until done
- sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to execute
- long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
+ long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
+ long delay;
- // special case: user's onTick took more than interval to
- // complete, skip to next interval
- while (delay < 0) delay += mCountdownInterval;
+ if (millisLeft < mCountdownInterval) {
+ // just delay until done
+ delay = millisLeft - lastTickDuration;
+
+ // special case: user's onTick took more than interval to
+ // complete, trigger onFinish without delay
+ if (delay < 0) delay = 0;
+ } else {
+ delay = mCountdownInterval - lastTickDuration;
+
+ // special case: user's onTick took more than interval to
+ // complete, skip to next interval
+ while (delay < 0) delay += mCountdownInterval;
+ }
sendMessageDelayed(obtainMessage(MSG), delay);
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 0e7da63..481b2dc 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -16,6 +16,7 @@
package android.os;
+import java.util.ArrayList;
import libcore.util.NativeAllocationRegistry;
/** @hide */
@@ -39,10 +40,12 @@
int code, HwParcel request, HwParcel reply, int flags);
public native final void registerService(
- String serviceName, int versionMajor, int versionMinor);
+ ArrayList<String> interfaceChain,
+ String serviceName);
public static native final IHwBinder getService(
- String serviceName, int versionMajor, int versionMinor);
+ String iface,
+ String serviceName);
// Returns address of the "freeFunction".
private static native final long native_init();
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 3546e17..819afb4 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -77,6 +77,7 @@
public boolean register(E callback) {
return register(callback, null);
}
+
/**
* Add a new callback to the list. This callback will remain in the list
* until a corresponding call to {@link #unregister} or its hosting process
@@ -326,4 +327,27 @@
return mCallbacks.size();
}
}
+
+ /**
+ * Return the cookies associated with a currently registered callback. Note that this is
+ * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
+ * interchangeably with it. This method returns the current cookied registered at the given
+ * index, not the current broadcast state. This means that it is not itself thread-safe:
+ * any call to {@link #register} or {@link #unregister} will change these indices, so you
+ * must do your own thread safety between these to protect from such changes.
+ *
+ * @param index Index of which registration cookie to return from 0 to
+ * {@link #getRegisteredCallbackCount()}.
+ *
+ * @return Returns whatever cookie object is associated with this index, or null if
+ * {@link #kill()} has been called.
+ */
+ public Object getRegisteredCallbackCookie(int index) {
+ synchronized (mCallbacks) {
+ if (mKilled) {
+ return null;
+ }
+ return mCallbacks.valueAt(index).mCookie;
+ }
+ }
}
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 640105c..e11494d 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -36,7 +36,8 @@
}
// Find the service manager
- sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
+ sServiceManager = ServiceManagerNative
+ .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
@@ -52,7 +53,7 @@
if (service != null) {
return service;
} else {
- return getIServiceManager().getService(name);
+ return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
@@ -117,7 +118,7 @@
if (service != null) {
return service;
} else {
- return getIServiceManager().checkService(name);
+ return Binder.allowBlocking(getIServiceManager().checkService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in checkService", e);
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index e9a3936..ef79b66 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -17,7 +17,6 @@
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.app.IActivityManager;
@@ -1606,7 +1605,7 @@
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (am == null) {
Log.d(TAG, "No activity manager; failed to Dropbox violation.");
} else {
@@ -1943,7 +1942,7 @@
// We restore the current policy below, in the finally block.
setThreadPolicyMask(0);
- ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
+ ActivityManager.getService().handleApplicationStrictModeViolation(
RuntimeInit.getApplicationObject(),
violationMaskSubset,
info);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 15dd282..50eb7cf 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -26,7 +26,6 @@
import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -983,7 +982,7 @@
public boolean isUserRunning(int userId) {
// TODO Switch to using UMS internal isUserRunning
try {
- return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
+ return ActivityManager.getService().isUserRunning(userId, 0);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -999,7 +998,7 @@
public boolean isUserRunningOrStopping(UserHandle user) {
try {
// TODO: reconcile stopped vs stopping?
- return ActivityManagerNative.getDefault().isUserRunning(
+ return ActivityManager.getService().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_OR_STOPPED);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1016,7 +1015,7 @@
@Deprecated
public boolean isUserRunningAndLocked(UserHandle user) {
try {
- return ActivityManagerNative.getDefault().isUserRunning(
+ return ActivityManager.getService().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1033,7 +1032,7 @@
@Deprecated
public boolean isUserRunningAndUnlocked(UserHandle user) {
try {
- return ActivityManagerNative.getDefault().isUserRunning(
+ return ActivityManager.getService().isUserRunning(
user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1080,7 +1079,7 @@
/** {@hide} */
public boolean isUserUnlocked(@UserIdInt int userId) {
try {
- return ActivityManagerNative.getDefault().isUserRunning(userId,
+ return ActivityManager.getService().isUserRunning(userId,
ActivityManager.FLAG_AND_UNLOCKED);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl
index 61ba4d5..a86ba59 100644
--- a/core/java/android/os/storage/IObbActionListener.aidl
+++ b/core/java/android/os/storage/IObbActionListener.aidl
@@ -17,7 +17,7 @@
package android.os.storage;
/**
- * Callback class for receiving events from MountService about Opaque Binary
+ * Callback class for receiving events from StorageManagerService about Opaque Binary
* Blobs (OBBs).
*
* Don't change the existing transaction Ids as they could be used in the native code.
diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IStorageEventListener.aidl
similarity index 89%
rename from core/java/android/os/storage/IMountServiceListener.aidl
rename to core/java/android/os/storage/IStorageEventListener.aidl
index 0e20cd3..4ba1dbe 100644
--- a/core/java/android/os/storage/IMountServiceListener.aidl
+++ b/core/java/android/os/storage/IStorageEventListener.aidl
@@ -21,15 +21,15 @@
import android.os.storage.VolumeRecord;
/**
- * Callback class for receiving events from MountService.
+ * Callback class for receiving events from StorageManagerService.
*
* Don't change the existing transaction Ids as they could be used in the native code.
* When adding a new method, assign the next available transaction id.
*
- * @hide - Applications should use IStorageEventListener for storage event
- * callbacks.
+ * @hide - Applications should use {@link android.os.storage.StorageEventListener} class for
+ * storage event callbacks.
*/
-oneway interface IMountServiceListener {
+oneway interface IStorageEventListener {
/**
* Detection state of USB Mass Storage has changed
*
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IStorageManager.aidl
similarity index 90%
rename from core/java/android/os/storage/IMountService.aidl
rename to core/java/android/os/storage/IStorageManager.aidl
index 390df99..98cbce6 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -19,8 +19,8 @@
import android.content.pm.IPackageMoveObserver;
import android.os.ParcelFileDescriptor;
import android.os.storage.DiskInfo;
-import android.os.storage.IMountServiceListener;
-import android.os.storage.IMountShutdownObserver;
+import android.os.storage.IStorageEventListener;
+import android.os.storage.IStorageShutdownObserver;
import android.os.storage.IObbActionListener;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
@@ -34,15 +34,15 @@
* @hide - Applications should use android.os.storage.StorageManager to access
* storage functions.
*/
-interface IMountService {
+interface IStorageManager {
/**
- * Registers an IMountServiceListener for receiving async notifications.
+ * Registers an IStorageEventListener for receiving async notifications.
*/
- void registerListener(IMountServiceListener listener) = 0;
+ void registerListener(IStorageEventListener listener) = 0;
/**
- * Unregisters an IMountServiceListener
+ * Unregisters an IStorageEventListener
*/
- void unregisterListener(IMountServiceListener listener) = 1;
+ void unregisterListener(IStorageEventListener listener) = 1;
/**
* Returns true if a USB mass storage host is connected
*/
@@ -58,7 +58,7 @@
boolean isUsbMassStorageEnabled() = 4;
/**
* Mount external storage at given mount point. Returns an int consistent
- * with MountServiceResultCode
+ * with StorageResultCode
*/
int mountVolume(in String mountPoint) = 5;
/**
@@ -74,7 +74,7 @@
void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 6;
/**
* Format external storage given a mount point. Returns an int consistent
- * with MountServiceResultCode
+ * with StorageResultCode
*/
int formatVolume(in String mountPoint) = 7;
/**
@@ -87,30 +87,30 @@
String getVolumeState(in String mountPoint) = 9;
/*
* Creates a secure container with the specified parameters. Returns an int
- * consistent with MountServiceResultCode
+ * consistent with StorageResultCode
*/
int createSecureContainer(in String id, int sizeMb, in String fstype, in String key,
int ownerUid, boolean external) = 10;
/*
* Finalize a container which has just been created and populated. After
* finalization, the container is immutable. Returns an int consistent with
- * MountServiceResultCode
+ * StorageResultCode
*/
int finalizeSecureContainer(in String id) = 11;
/*
* Destroy a secure container, and free up all resources associated with it.
* NOTE: Ensure all references are released prior to deleting. Returns an
- * int consistent with MountServiceResultCode
+ * int consistent with StorageResultCode
*/
int destroySecureContainer(in String id, boolean force) = 12;
/*
* Mount a secure container with the specified key and owner UID. Returns an
- * int consistent with MountServiceResultCode
+ * int consistent with StorageResultCode
*/
int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 13;
/*
* Unount a secure container. Returns an int consistent with
- * MountServiceResultCode
+ * StorageResultCode
*/
int unmountSecureContainer(in String id, boolean force) = 14;
/*
@@ -119,7 +119,7 @@
boolean isSecureContainerMounted(in String id) = 15;
/*
* Rename an unmounted secure container. Returns an int consistent with
- * MountServiceResultCode
+ * StorageResultCode
*/
int renameSecureContainer(in String oldId, in String newId) = 16;
/*
@@ -131,19 +131,19 @@
*/
String[] getSecureContainerList() = 18;
/**
- * Shuts down the MountService and gracefully unmounts all external media.
+ * Shuts down the StorageManagerService and gracefully unmounts all external media.
* Invokes call back once the shutdown is complete.
*/
- void shutdown(IMountShutdownObserver observer) = 19;
+ void shutdown(IStorageShutdownObserver observer) = 19;
/**
- * Call into MountService by PackageManager to notify that its done
+ * Call into StorageManagerService by PackageManager to notify that its done
* processing the media status update request.
*/
void finishMediaUpdate() = 20;
/**
* Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
* only allows the calling process's UID access to the contents.
- * MountService will call back to the supplied IObbActionListener to inform
+ * StorageManagerService will call back to the supplied IObbActionListener to inform
* it of the terminal state of the call.
*/
void mountObb(in String rawPath, in String canonicalPath, in String key,
@@ -151,7 +151,7 @@
/**
* Unmounts an Opaque Binary Blob (OBB). When the force flag is specified,
* any program using it will be forcibly killed to unmount the image.
- * MountService will call back to the supplied IObbActionListener to inform
+ * StorageManagerService will call back to the supplied IObbActionListener to inform
* it of the terminal state of the call.
*/
void unmountObb(in String rawPath, boolean force, IObbActionListener token, int nonce) = 22;
@@ -209,7 +209,7 @@
int verifyEncryptionPassword(in String password) = 32;
/*
* Fix permissions in a container which has just been created and populated.
- * Returns an int consistent with MountServiceResultCode
+ * Returns an int consistent with StorageResultCode
*/
int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 33;
/**
diff --git a/core/java/android/os/storage/IMountShutdownObserver.aidl b/core/java/android/os/storage/IStorageShutdownObserver.aidl
similarity index 91%
rename from core/java/android/os/storage/IMountShutdownObserver.aidl
rename to core/java/android/os/storage/IStorageShutdownObserver.aidl
index f3e1654..b284217 100644
--- a/core/java/android/os/storage/IMountShutdownObserver.aidl
+++ b/core/java/android/os/storage/IStorageShutdownObserver.aidl
@@ -24,9 +24,9 @@
*
* @hide - For internal consumption only.
*/
-interface IMountShutdownObserver {
+interface IStorageShutdownObserver {
/**
- * This method is called when the shutdown of MountService completed.
+ * This method is called when the shutdown of StorageManagerService completed.
*
* @param statusCode indicates success or failure of the shutdown.
*/
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 1942fde..0472e02 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -152,7 +152,7 @@
/** @hide Underlying data is corrupt */
public static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
- private static volatile IMountService sMountService = null;
+ private static volatile IStorageManager sStorageManager = null;
// TODO: the location of the primary storage block varies from device to device, so we need to
// try the most likely candidates - a long-term solution would be a device-specific vold
@@ -166,13 +166,13 @@
private final Context mContext;
private final ContentResolver mResolver;
- private final IMountService mMountService;
+ private final IStorageManager mStorageManager;
private final Looper mLooper;
private final AtomicInteger mNextNonce = new AtomicInteger(0);
private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
- private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
+ private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
Handler.Callback {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
@@ -374,7 +374,7 @@
mContext = context;
mResolver = context.getContentResolver();
mLooper = looper;
- mMountService = IMountService.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
+ mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
}
/**
@@ -389,7 +389,7 @@
final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
mLooper);
try {
- mMountService.registerListener(delegate);
+ mStorageManager.registerListener(delegate);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -410,7 +410,7 @@
final StorageEventListenerDelegate delegate = i.next();
if (delegate.mCallback == listener) {
try {
- mMountService.unregisterListener(delegate);
+ mStorageManager.unregisterListener(delegate);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -488,7 +488,7 @@
try {
final String canonicalPath = new File(rawPath).getCanonicalPath();
final int nonce = mObbActionListener.addListener(listener);
- mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
+ mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
return true;
} catch (IOException e) {
throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
@@ -523,7 +523,7 @@
try {
final int nonce = mObbActionListener.addListener(listener);
- mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
+ mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -540,7 +540,7 @@
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
try {
- return mMountService.isObbMounted(rawPath);
+ return mStorageManager.isObbMounted(rawPath);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -559,7 +559,7 @@
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
try {
- return mMountService.getMountedObbPath(rawPath);
+ return mStorageManager.getMountedObbPath(rawPath);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -568,7 +568,7 @@
/** {@hide} */
public @NonNull List<DiskInfo> getDisks() {
try {
- return Arrays.asList(mMountService.getDisks());
+ return Arrays.asList(mStorageManager.getDisks());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -654,7 +654,7 @@
/** {@hide} */
public @NonNull List<VolumeInfo> getVolumes() {
try {
- return Arrays.asList(mMountService.getVolumes(0));
+ return Arrays.asList(mStorageManager.getVolumes(0));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -664,7 +664,7 @@
public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
try {
final ArrayList<VolumeInfo> res = new ArrayList<>();
- for (VolumeInfo vol : mMountService.getVolumes(0)) {
+ for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
res.add(vol);
}
@@ -678,7 +678,7 @@
/** {@hide} */
public @NonNull List<VolumeRecord> getVolumeRecords() {
try {
- return Arrays.asList(mMountService.getVolumeRecords(0));
+ return Arrays.asList(mStorageManager.getVolumeRecords(0));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -721,7 +721,7 @@
/** {@hide} */
public void mount(String volId) {
try {
- mMountService.mount(volId);
+ mStorageManager.mount(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -730,7 +730,7 @@
/** {@hide} */
public void unmount(String volId) {
try {
- mMountService.unmount(volId);
+ mStorageManager.unmount(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -739,7 +739,7 @@
/** {@hide} */
public void format(String volId) {
try {
- mMountService.format(volId);
+ mStorageManager.format(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -748,7 +748,7 @@
/** {@hide} */
public long benchmark(String volId) {
try {
- return mMountService.benchmark(volId);
+ return mStorageManager.benchmark(volId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -757,7 +757,7 @@
/** {@hide} */
public void partitionPublic(String diskId) {
try {
- mMountService.partitionPublic(diskId);
+ mStorageManager.partitionPublic(diskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -766,7 +766,7 @@
/** {@hide} */
public void partitionPrivate(String diskId) {
try {
- mMountService.partitionPrivate(diskId);
+ mStorageManager.partitionPrivate(diskId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -775,7 +775,7 @@
/** {@hide} */
public void partitionMixed(String diskId, int ratio) {
try {
- mMountService.partitionMixed(diskId, ratio);
+ mStorageManager.partitionMixed(diskId, ratio);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -795,7 +795,7 @@
try {
// TODO: switch to explicit wipe command when we have it,
// for now rely on the fact that vfat format does a wipe
- mMountService.partitionPublic(diskId);
+ mStorageManager.partitionPublic(diskId);
} catch (Exception e) {
Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
}
@@ -808,7 +808,7 @@
/** {@hide} */
public void setVolumeNickname(String fsUuid, String nickname) {
try {
- mMountService.setVolumeNickname(fsUuid, nickname);
+ mStorageManager.setVolumeNickname(fsUuid, nickname);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -817,7 +817,7 @@
/** {@hide} */
public void setVolumeInited(String fsUuid, boolean inited) {
try {
- mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
+ mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
VolumeRecord.USER_FLAG_INITED);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -827,7 +827,7 @@
/** {@hide} */
public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
try {
- mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
+ mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
VolumeRecord.USER_FLAG_SNOOZED);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -837,7 +837,7 @@
/** {@hide} */
public void forgetVolume(String fsUuid) {
try {
- mMountService.forgetVolume(fsUuid);
+ mStorageManager.forgetVolume(fsUuid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -851,7 +851,7 @@
*/
public String getPrimaryStorageUuid() {
try {
- return mMountService.getPrimaryStorageUuid();
+ return mStorageManager.getPrimaryStorageUuid();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -865,7 +865,7 @@
*/
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
try {
- mMountService.setPrimaryStorageUuid(volumeUuid, callback);
+ mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -982,7 +982,7 @@
/** {@hide} */
public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
- final IMountService mountService = IMountService.Stub.asInterface(
+ final IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
try {
String packageName = ActivityThread.currentOpPackageName();
@@ -1003,7 +1003,7 @@
if (uid <= 0) {
return new StorageVolume[0];
}
- return mountService.getVolumeList(uid, packageName, flags);
+ return storageManager.getVolumeList(uid, packageName, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1085,7 +1085,7 @@
/** {@hide} */
public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
try {
- mMountService.createUserKey(userId, serialNumber, ephemeral);
+ mStorageManager.createUserKey(userId, serialNumber, ephemeral);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1094,7 +1094,7 @@
/** {@hide} */
public void destroyUserKey(int userId) {
try {
- mMountService.destroyUserKey(userId);
+ mStorageManager.destroyUserKey(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1103,7 +1103,7 @@
/** {@hide} */
public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
try {
- mMountService.unlockUserKey(userId, serialNumber, token, secret);
+ mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1112,7 +1112,7 @@
/** {@hide} */
public void lockUserKey(int userId) {
try {
- mMountService.lockUserKey(userId);
+ mStorageManager.lockUserKey(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1121,7 +1121,7 @@
/** {@hide} */
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
try {
- mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
+ mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1130,7 +1130,7 @@
/** {@hide} */
public void destroyUserStorage(String volumeUuid, int userId, int flags) {
try {
- mMountService.destroyUserStorage(volumeUuid, userId, flags);
+ mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1138,17 +1138,17 @@
/** {@hide} */
public static boolean isUserKeyUnlocked(int userId) {
- if (sMountService == null) {
- sMountService = IMountService.Stub
+ if (sStorageManager == null) {
+ sStorageManager = IStorageManager.Stub
.asInterface(ServiceManager.getService("mount"));
}
- if (sMountService == null) {
+ if (sStorageManager == null) {
Slog.w(TAG, "Early during boot, assuming locked");
return false;
}
final long token = Binder.clearCallingIdentity();
try {
- return sMountService.isUserKeyUnlocked(userId);
+ return sStorageManager.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
@@ -1224,9 +1224,9 @@
}
try {
- IMountService mountService = IMountService.Stub.asInterface(
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
- return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT;
+ return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
} catch (RemoteException e) {
Log.e(TAG, "Error getting encryption type");
return false;
@@ -1280,10 +1280,10 @@
/** {@hide} */
public static File maybeTranslateEmulatedPathToInternal(File path) {
- final IMountService mountService = IMountService.Stub.asInterface(
+ final IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
try {
- final VolumeInfo[] vols = mountService.getVolumes(0);
+ final VolumeInfo[] vols = storageManager.getVolumes(0);
for (VolumeInfo vol : vols) {
if ((vol.getType() == VolumeInfo.TYPE_EMULATED
|| vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
@@ -1303,7 +1303,7 @@
/** {@hide} */
public ParcelFileDescriptor mountAppFuse(String name) {
try {
- return mMountService.mountAppFuse(name);
+ return mStorageManager.mountAppFuse(name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1319,7 +1319,7 @@
/** @hide */
public static final int CRYPT_TYPE_PIN = 3;
- // Constants for the data available via MountService.getField.
+ // Constants for the data available via StorageManagerService.getField.
/** @hide */
public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
/** @hide */
diff --git a/core/java/android/os/storage/MountServiceInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
similarity index 98%
rename from core/java/android/os/storage/MountServiceInternal.java
rename to core/java/android/os/storage/StorageManagerInternal.java
index 17aaef9..d102b19 100644
--- a/core/java/android/os/storage/MountServiceInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -21,7 +21,7 @@
*
* @hide Only for use within the system server.
*/
-public abstract class MountServiceInternal {
+public abstract class StorageManagerInternal {
/**
* Policy that influences how external storage is mounted and reported.
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 8e7db31..c843887 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -18,7 +18,7 @@
/**
* Class that provides access to constants returned from StorageManager
- * and lower level MountService APIs.
+ * and lower level StorageManagerService APIs.
*
* @hide
*/
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 7b0d2a4..46f2d38 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -332,7 +332,7 @@
* {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS},
* {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES},
* {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or
- * {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the
+ * {@link Environment#DIRECTORY_DOCUMENTS}, or {@code null} to request access to the
* entire volume.
* @return intent to request access, or {@code null} if the requested directory is invalid for
* that volume.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index f86193f..383cae1 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -156,6 +156,10 @@
private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES);
/** {@hide} */
+ public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY =
+ "com.android.externalstorage.documents";
+
+ /** {@hide} */
public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui";
/**
@@ -699,7 +703,7 @@
public static Uri buildHomeUri() {
// TODO: Avoid this type of interpackage copying. Added here to avoid
// direct coupling, but not ideal.
- return DocumentsContract.buildRootUri("com.android.externalstorage.documents", "home");
+ return DocumentsContract.buildRootUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, "home");
}
/**
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index b826584..a280e59 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -41,6 +41,8 @@
public static final class Impl implements BaseColumns {
private Impl() {}
+ public static final String AUTHORITY = "downloads";
+
/**
* The permission to access the download manager
*/
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index de19f81..c4684e7 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -18,11 +18,13 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.UriPermission;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteException;
@@ -32,17 +34,23 @@
import android.media.MiniThumbFile;
import android.media.ThumbnailUtils;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.service.media.CameraPrewarmService;
import android.util.Log;
+import libcore.io.IoUtils;
+
+import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
+import java.util.List;
/**
* The Media provider contains meta data for all available media on both internal
@@ -2297,4 +2305,86 @@
}
return null;
}
+
+ /**
+ * Gets a URI backed by a {@link DocumentsProvider} that points to the same media
+ * file as the specified mediaUri. This allows apps who have permissions to access
+ * media files in Storage Access Framework to perform file operations through that
+ * on media files.
+ * <p>
+ * Note: this method doesn't grant any URI permission. Callers need to obtain
+ * permission before calling this method. One way to obtain permission is through
+ * a 3-step process:
+ * <ol>
+ * <li>Call {@link android.os.storage.StorageManager#getStorageVolume(File)} to
+ * obtain the {@link android.os.storage.StorageVolume} of a media file;</li>
+ *
+ * <li>Invoke the intent returned by
+ * {@link android.os.storage.StorageVolume#createAccessIntent(String)} to
+ * obtain the access of the volume or one of its specific subdirectories;</li>
+ *
+ * <li>Check whether permission is granted and take persistent permission.</li>
+ * </ol>
+ * @param mediaUri the media URI which document URI is requested
+ * @return the document URI
+ */
+ public static Uri getDocumentUri(Context context, Uri mediaUri) {
+
+ try {
+ final ContentResolver resolver = context.getContentResolver();
+
+ final String path = getFilePath(resolver, mediaUri);
+ final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
+
+ return getDocumentUri(resolver, path, uriPermissions);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ private static String getFilePath(ContentResolver resolver, Uri mediaUri)
+ throws RemoteException {
+
+ try (ContentProviderClient client =
+ resolver.acquireUnstableContentProviderClient(AUTHORITY)) {
+ final Cursor c = client.query(
+ mediaUri,
+ new String[]{ MediaColumns.DATA },
+ null, /* selection */
+ null, /* selectionArg */
+ null /* sortOrder */);
+
+ final String path;
+ try {
+ if (c.getCount() == 0) {
+ throw new IllegalStateException("Not found media file under URI: " + mediaUri);
+ }
+
+ if (!c.moveToFirst()) {
+ throw new IllegalStateException("Failed to move cursor to the first item.");
+ }
+
+ path = c.getString(0);
+ } finally {
+ IoUtils.closeQuietly(c);
+ }
+
+ return path;
+ }
+ }
+
+ private static Uri getDocumentUri(
+ ContentResolver resolver, String path, List<UriPermission> uriPermissions)
+ throws RemoteException {
+
+ try (ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putParcelableList(
+ DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY + ".extra.uriPermissions",
+ uriPermissions);
+ final Bundle out = client.call("getDocumentId", path, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 22336c6..afbc09b 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4715,6 +4715,13 @@
public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
/**
+ * The currently selected auto-fill service flattened ComponentName.
+ * @hide
+ */
+ @TestApi
+ public static final String AUTO_FILL_SERVICE = "auto_fill_service";
+
+ /**
* bluetooth HCI snoop log configuration
* @hide
*/
@@ -5847,7 +5854,8 @@
"search_per_source_concurrent_query_limit";
/**
- * Whether or not alert sounds are played on MountService events. (0 = false, 1 = true)
+ * Whether or not alert sounds are played on StorageManagerService events.
+ * (0 = false, 1 = true)
* @hide
*/
public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd";
@@ -6114,6 +6122,15 @@
public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled";
/**
+ * Name of the service components that the current user has explicitly allowed to
+ * see and assist with all of the user's notifications.
+ *
+ * @hide
+ */
+ public static final String ENABLED_NOTIFICATION_ASSISTANT =
+ "enabled_notification_assistant";
+
+ /**
* Names of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
*
@@ -8613,13 +8630,6 @@
public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
/**
- * @hide
- * If not 0, the activity manager will implement a looser version of background
- * check that is more compatible with existing apps.
- */
- public static final String LENIENT_BACKGROUND_CHECK = "lenient_background_check";
-
- /**
* Use Dock audio output for media:
* 0 = disabled
* 1 = enabled
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
new file mode 100644
index 0000000..3734831
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import android.annotation.SdkConstant;
+import android.app.Activity;
+import android.app.Service;
+import android.app.assist.AssistStructure;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Log;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.os.SomeArgs;
+
+/**
+ * Top-level service of the current auto-fill service for a given user.
+ *
+ * <p>Apps providing auto-fill capabilities must extend this service.
+ */
+public abstract class AutoFillService extends Service {
+
+ static final String TAG = "AutoFillService";
+ static final boolean DEBUG = true; // TODO: set to false once stable
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+
+ private static final int MSG_CONNECT = 1;
+ private static final int MSG_AUTO_FILL_ACTIVITY = 2;
+ private static final int MSG_DISCONNECT = 3;
+
+ private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ final AssistStructure structure = resultData
+ .getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
+
+ final IBinder binder = resultData
+ .getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+
+ mHandlerCaller
+ .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, binder).sendToTarget();
+ }
+
+ };
+
+ private final IAutoFillService mInterface = new IAutoFillService.Stub() {
+ @Override
+ public void onConnected() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT));
+ }
+
+ @Override
+ public IResultReceiver getAssistReceiver() {
+ return mAssistReceiver;
+ }
+
+ @Override
+ public void onDisconnected() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT));
+ }
+ };
+
+ private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
+
+ @Override
+ public void executeMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CONNECT: {
+ onConnected();
+ break;
+ } case MSG_AUTO_FILL_ACTIVITY: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final AssistStructure structure = (AssistStructure) args.arg1;
+ final IBinder binder = (IBinder) args.arg2;
+ requestAutoFill(structure, binder);
+ break;
+ } case MSG_DISCONNECT: {
+ onDisconnected();
+ break;
+ } default: {
+ Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
+ }
+ }
+ }
+ };
+
+ private HandlerCaller mHandlerCaller;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Log.w(TAG, "Tried to bind to wrong intent: " + intent);
+ return null;
+ }
+
+ /**
+ * Called when the Android System connects to service.
+ *
+ * <p>You should generally do initialization here rather than in {@link #onCreate}.
+ */
+ public void onConnected() {
+ if (DEBUG) Log.d(TAG, "onConnected()");
+ }
+
+ /**
+ * Handles an auto-fill request.
+ *
+ * @param structure {@link Activity}'s view structure .
+ * @param cancellationSignal signal for observing cancel requests.
+ * @param callback object used to fulllfill the request.
+ */
+ public abstract void onFillRequest(AssistStructure structure,
+ CancellationSignal cancellationSignal, FillCallback callback);
+
+ private void requestAutoFill(AssistStructure structure, IBinder binder) {
+ final FillCallback callback = new FillCallback(binder);
+ // TODO: hook up the cancelationSignal
+ onFillRequest(structure, new CancellationSignal(), callback);
+ }
+
+ /**
+ * Called when the Android System disconnects from the service.
+ *
+ * <p> At this point this service may no longer be an active {@link AutoFillService}.
+ */
+ public void onDisconnected() {
+ if (DEBUG) Log.d(TAG, "onDisconnected()");
+ }
+}
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
new file mode 100644
index 0000000..fe21615
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+
+/** @hide */
+public final class AutoFillServiceInfo {
+
+ private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
+ throws PackageManager.NameNotFoundException {
+ try {
+ final ServiceInfo si =
+ AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle);
+ if (si != null) {
+ return si;
+ }
+ } catch (RemoteException e) {
+ }
+ throw new PackageManager.NameNotFoundException(comp.toString());
+ }
+
+ private String mParseError;
+
+ private ServiceInfo mServiceInfo;
+
+ private AutoFillServiceInfo(ServiceInfo si) {
+ if (si == null) {
+ mParseError = "Service not available";
+ return;
+ }
+ if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
+ mParseError = "Service does not require permission "
+ + Manifest.permission.BIND_AUTO_FILL;
+ return;
+ }
+
+ mServiceInfo = si;
+ }
+
+ public AutoFillServiceInfo(ComponentName comp, int userHandle)
+ throws PackageManager.NameNotFoundException {
+ this(getServiceInfoOrThrow(comp, userHandle));
+ }
+
+ public String getParseError() {
+ return mParseError;
+ }
+
+ public ServiceInfo getServiceInfo() {
+ return mServiceInfo;
+ }
+}
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
new file mode 100644
index 0000000..2308440
--- /dev/null
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.service.autofill.AutoFillService.DEBUG;
+import static android.service.autofill.AutoFillService.TAG;
+
+import android.app.Activity;
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Handles auto-fill requests from the {@link AutoFillService} into the {@link Activity} being
+ * auto-filled.
+ */
+public final class FillCallback {
+
+ private final IAutoFillCallback mCallback;
+
+ /** @hide */
+ FillCallback(IBinder binder) {
+ mCallback = IAutoFillCallback.Stub.asInterface(binder);
+ }
+
+ /**
+ * Auto-fills the {@link Activity}.
+ *
+ * @throws RuntimeException if an error occurred while auto-filling it.
+ */
+ public void onSuccess(FillData data) {
+ if (DEBUG) Log.d(TAG, "onSuccess(): data=" + data);
+
+ Preconditions.checkArgument(data != null, "data cannot be null");
+
+ try {
+ mCallback.autofill(data.asList());
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ public void onFailure(CharSequence message) {
+ if (DEBUG) Log.d(TAG, "onFailure(): message=" + message);
+
+ Preconditions.checkArgument(message != null, "message cannot be null");
+
+ try {
+ mCallback.showError(message.toString());
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Data used to fill the fields of an {@link Activity}.
+ *
+ * <p>This class is immutable.
+ */
+ public static final class FillData {
+
+ private final List<FillableInputField> mList;
+
+ private FillData(Builder builder) {
+ final int size = builder.mFields.size();
+ final List<FillableInputField> list = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ list.add(builder.mFields.valueAt(i));
+ }
+ mList = Collections.unmodifiableList(list);
+ // TODO: use FastImmutableArraySet or a similar structure instead?
+ }
+
+ /**
+ * Gets the response as a {@code List} so it can be used in a binder call.
+ */
+ List<FillableInputField> asList() {
+ return mList;
+ }
+
+ @Override
+ public String toString() {
+ return "[AutoFillResponse: " + mList + "]";
+ }
+
+ /**
+ * Builder for {@link FillData} objects.
+ *
+ * <p>Typical usage:
+ *
+ * <pre class="prettyprint">
+ * FillCallback.FillData data = new FillCallback.FillData.Builder()
+ * .setTextField(id1, "value 1")
+ * .setTextField(id2, "value 2")
+ * .build()
+ * </pre>
+ */
+ public static class Builder {
+ private final SparseArray<FillableInputField> mFields = new SparseArray<>();
+
+ /**
+ * Auto-fills a text field.
+ *
+ * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
+ * @param text text to be auto-filled.
+ * @return same builder so it can be chained.
+ */
+ public Builder setTextField(int id, String text) {
+ mFields.put(id, FillableInputField.forText(id, text));
+ return this;
+ }
+
+ /**
+ * Builds a new {@link FillData} instance.
+ */
+ public FillData build() {
+ return new FillData(this);
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/autofill/FillableInputField.java b/core/java/android/service/autofill/FillableInputField.java
new file mode 100644
index 0000000..62950b4
--- /dev/null
+++ b/core/java/android/service/autofill/FillableInputField.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.app.assist.AssistStructure.ViewNode;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a view field that can be auto-filled.
+ *
+ * <p>Currently only text-fields are supported, so the value of the field can be obtained through
+ * {@link #getValue()}.
+ *
+ * @hide
+ */
+public final class FillableInputField implements Parcelable {
+
+ private final int mId;
+ private final String mValue;
+
+ private FillableInputField(int id, String value) {
+ mId = id;
+ mValue = value;
+ }
+
+ private FillableInputField(Parcel parcel) {
+ mId = parcel.readInt();
+ mValue = parcel.readString();
+ }
+
+ /**
+ * Gets the view id as returned by {@link ViewNode#getAutoFillId()}.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Gets the value of this field.
+ */
+ public String getValue() {
+ return mValue;
+
+ }
+
+ @Override
+ public String toString() {
+ return "[AutoFillField: " + mId + "=" + mValue + "]";
+ }
+
+ /**
+ * Creates an {@code AutoFillField} for a text field.
+ *
+ * @param id view id as returned by {@link ViewNode#getAutoFillId()}.
+ * @param text value to be auto-filled.
+ */
+ public static FillableInputField forText(int id, String text) {
+ return new FillableInputField(id, text);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mId);
+ parcel.writeString(mValue);
+ }
+
+ public static final Parcelable.Creator<FillableInputField> CREATOR =
+ new Parcelable.Creator<FillableInputField>() {
+ @Override
+ public FillableInputField createFromParcel(Parcel source) {
+ return new FillableInputField(source);
+ }
+
+ @Override
+ public FillableInputField[] newArray(int size) {
+ return new FillableInputField[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/IAutoFillCallback.aidl b/core/java/android/service/autofill/IAutoFillCallback.aidl
new file mode 100644
index 0000000..db8ef96
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+interface IAutoFillCallback {
+ void autofill(in List values);
+ void showError(String message);
+}
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
new file mode 100644
index 0000000..cab073f
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.os.Bundle;
+
+/**
+ * Mediator between apps being auto-filled and auto-fill service implementations.
+ *
+ * {@hide}
+ */
+interface IAutoFillManagerService {
+
+ /**
+ * Request auto-fill on the top activity of a given user.
+ *
+ * @param userId user handle.
+ * @param activityToken optional token of activity that needs to be on top.
+ */
+ void requestAutoFill(int userId, IBinder activityToken);
+}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
new file mode 100644
index 0000000..e3e911c
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.app.assist.AssistStructure;
+import android.os.Bundle;
+import android.service.autofill.IAutoFillCallback;
+import com.android.internal.os.IResultReceiver;
+
+/**
+ * @hide
+ */
+interface IAutoFillService {
+ void onConnected();
+ void onDisconnected();
+ IResultReceiver getAssistReceiver();
+}
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 4a956c6..4b272e9 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -22,11 +22,8 @@
import android.os.Parcelable;
/**
- * Ranking updates from the Ranker.
- *
- * @hide
+ * Ranking updates from the Assistant.
*/
-@SystemApi
public final class Adjustment implements Parcelable {
private final String mPackage;
private final String mKey;
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 8c35901..f639c0d 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -28,7 +28,7 @@
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
- in NotificationRankingUpdate update);
+ in NotificationRankingUpdate update, int reason);
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
@@ -38,5 +38,4 @@
void onNotificationVisibilityChanged(String key, long time, boolean visible);
void onNotificationClick(String key, long time);
void onNotificationActionClick(String key, long time, int actionIndex);
- void onNotificationRemovedReason(String key, long time, int reason);
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
new file mode 100644
index 0000000..4e00c64
--- /dev/null
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import android.annotation.SdkConstant;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.os.SomeArgs;
+
+import java.util.List;
+
+/**
+ * A service that helps the user manage notifications.
+ */
+public abstract class NotificationAssistantService extends NotificationListenerService {
+ private static final String TAG = "NotificationAssistants";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE
+ = "android.service.notification.NotificationAssistantService";
+
+ private Handler mHandler;
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ mHandler = new MyHandler(getContext().getMainLooper());
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (mWrapper == null) {
+ mWrapper = new NotificationAssistantServiceWrapper();
+ }
+ return mWrapper;
+ }
+
+ /**
+ * A notification was posted by an app. Called before alert.
+ *
+ * @param sbn the new notification
+ * @param importance the initial importance of the notification.
+ * @param user true if the initial importance reflects an explicit user preference.
+ * @return an adjustment or null to take no action, within 100ms.
+ */
+ abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
+ int importance, boolean user);
+
+ /**
+ * Updates a notification. N.B. this won’t cause
+ * an existing notification to alert, but might allow a future update to
+ * this notification to alert.
+ *
+ * @param adjustment the adjustment with an explanation
+ */
+ public final void adjustNotification(Adjustment adjustment) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().applyAdjustmentFromAssistantService(mWrapper, adjustment);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
+ * Updates existing notifications. Re-ranking won't occur until all adjustments are applied.
+ * N.B. this won’t cause an existing notification to alert, but might allow a future update to
+ * these notifications to alert.
+ *
+ * @param adjustments a list of adjustments with explanations
+ */
+ public final void adjustNotifications(List<Adjustment> adjustments) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().applyAdjustmentsFromAssistantService(mWrapper, adjustments);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
+ @Override
+ public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+ int importance, boolean user) {
+ StatusBarNotification sbn;
+ try {
+ sbn = sbnHolder.get();
+ } catch (RemoteException e) {
+ Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+ return;
+ }
+
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sbn;
+ args.argi1 = importance;
+ args.argi2 = user ? 1 : 0;
+ mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
+ args).sendToTarget();
+ }
+ }
+
+ private final class MyHandler extends Handler {
+ public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
+
+ public MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_NOTIFICATION_ENQUEUED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+ final int importance = args.argi1;
+ final boolean user = args.argi2 == 1;
+ args.recycle();
+ Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+ if (adjustment != null) {
+ adjustNotification(adjustment);
+ }
+ } break;
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index e606ebf..45011eb 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,7 @@
* </p>
*/
public abstract class NotificationListenerService extends Service {
+
// TAG = "NotificationListenerService[MySubclass]"
private final String TAG = NotificationListenerService.class.getSimpleName()
+ "[" + getClass().getSimpleName() + "]";
@@ -146,6 +147,48 @@
public static final int SUPPRESSED_EFFECT_SCREEN_ON =
NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+
+ // Notification cancellation reasons
+
+ /** Notification was canceled by the status bar reporting a click. */
+ public static final int REASON_DELEGATE_CLICK = 1;
+ /** Notification was canceled by the status bar reporting a user dismissal. */
+ public static final int REASON_DELEGATE_CANCEL = 2;
+ /** Notification was canceled by the status bar reporting a user dismiss all. */
+ public static final int REASON_DELEGATE_CANCEL_ALL = 3;
+ /** Notification was canceled by the status bar reporting an inflation error. */
+ public static final int REASON_DELEGATE_ERROR = 4;
+ /** Notification was canceled by the package manager modifying the package. */
+ public static final int REASON_PACKAGE_CHANGED = 5;
+ /** Notification was canceled by the owning user context being stopped. */
+ public static final int REASON_USER_STOPPED = 6;
+ /** Notification was canceled by the user banning the package. */
+ public static final int REASON_PACKAGE_BANNED = 7;
+ /** Notification was canceled by the app canceling this specific notification. */
+ public static final int REASON_APP_CANCEL = 8;
+ /** Notification was canceled by the app cancelling all its notifications. */
+ public static final int REASON_APP_CANCEL_ALL = 9;
+ /** Notification was canceled by a listener reporting a user dismissal. */
+ public static final int REASON_LISTENER_CANCEL = 10;
+ /** Notification was canceled by a listener reporting a user dismiss all. */
+ public static final int REASON_LISTENER_CANCEL_ALL = 11;
+ /** Notification was canceled because it was a member of a canceled group. */
+ public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
+ /** Notification was canceled because it was an invisible member of a group. */
+ public static final int REASON_GROUP_OPTIMIZATION = 13;
+ /** Notification was canceled by the device administrator suspending the package. */
+ public static final int REASON_PACKAGE_SUSPENDED = 14;
+ /** Notification was canceled by the owning managed profile being turned off. */
+ public static final int REASON_PROFILE_TURNED_OFF = 15;
+ /** Autobundled summary notification was canceled because its group was unbundled */
+ public static final int REASON_UNAUTOBUNDLED = 16;
+ /** Notification was canceled by the user banning the channel. */
+ public static final int REASON_CHANNEL_BANNED = 17;
+ /** Notification was snoozed. */
+ public static final int REASON_SNOOZED = 18;
+ /** Notification no longer visible because of user switch */
+ public static final int REASON_USER_SWITCH = 19;
+
/**
* The full trim of the StatusBarNotification including all its features.
*
@@ -282,6 +325,32 @@
onNotificationRemoved(sbn);
}
+
+ /**
+ * Implement this method to learn when notifications are removed and why.
+ * <p>
+ * This might occur because the user has dismissed the notification using system UI (or another
+ * notification listener) or because the app has withdrawn the notification.
+ * <p>
+ * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
+ * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
+ * fields such as {@link android.app.Notification#contentView} and
+ * {@link android.app.Notification#largeIcon}. However, all other fields on
+ * {@link StatusBarNotification}, sufficient to match this call with a prior call to
+ * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
+ *
+ ** @param sbn A data structure encapsulating at least the original information (tag and id)
+ * and source (package name) used to post the {@link android.app.Notification} that
+ * was just removed.
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications.
+ * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
+ */
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+ int reason) {
+ onNotificationRemoved(sbn, rankingMap);
+ }
+
/**
* Implement this method to learn about when the listener is enabled and connected to
* the notification manager. You are safe to call {@link #getActiveNotifications()}
@@ -927,7 +996,7 @@
@Override
public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
- NotificationRankingUpdate update) {
+ NotificationRankingUpdate update, int reason) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
@@ -941,6 +1010,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = sbn;
args.arg2 = mRankingMap;
+ args.arg3 = reason;
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
args).sendToTarget();
}
@@ -1003,12 +1073,6 @@
throws RemoteException {
// no-op in the listener
}
-
- @Override
- public void onNotificationRemovedReason(String key, long time, int reason)
- throws RemoteException {
- // no-op in the listener
- }
}
private void applyUpdateLocked(NotificationRankingUpdate update) {
@@ -1413,8 +1477,9 @@
SomeArgs args = (SomeArgs) msg.obj;
StatusBarNotification sbn = (StatusBarNotification) args.arg1;
RankingMap rankingMap = (RankingMap) args.arg2;
+ int reason = (int) args.arg3;
args.recycle();
- onNotificationRemoved(sbn, rankingMap);
+ onNotificationRemoved(sbn, rankingMap, reason);
} break;
case MSG_ON_LISTENER_CONNECTED: {
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
deleted file mode 100644
index 928d5d8..0000000
--- a/core/java/android/service/notification/NotificationRankerService.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.notification;
-
-import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-import com.android.internal.os.SomeArgs;
-
-import java.util.List;
-
-/**
- * A service that helps the user manage notifications. This class is only used to
- * extend the framework service and may not be implemented by non-framework components.
- * @hide
- */
-@SystemApi
-public abstract class NotificationRankerService extends NotificationListenerService {
- private static final String TAG = "NotificationRankers";
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE
- = "android.service.notification.NotificationRankerService";
-
- /** Notification was canceled by the status bar reporting a click. */
- public static final int REASON_DELEGATE_CLICK = 1;
-
- /** Notification was canceled by the status bar reporting a user dismissal. */
- public static final int REASON_DELEGATE_CANCEL = 2;
-
- /** Notification was canceled by the status bar reporting a user dismiss all. */
- public static final int REASON_DELEGATE_CANCEL_ALL = 3;
-
- /** Notification was canceled by the status bar reporting an inflation error. */
- public static final int REASON_DELEGATE_ERROR = 4;
-
- /** Notification was canceled by the package manager modifying the package. */
- public static final int REASON_PACKAGE_CHANGED = 5;
-
- /** Notification was canceled by the owning user context being stopped. */
- public static final int REASON_USER_STOPPED = 6;
-
- /** Notification was canceled by the user banning the package. */
- public static final int REASON_PACKAGE_BANNED = 7;
-
- /** Notification was canceled by the app canceling this specific notification. */
- public static final int REASON_APP_CANCEL = 8;
-
- /** Notification was canceled by the app cancelling all its notifications. */
- public static final int REASON_APP_CANCEL_ALL = 9;
-
- /** Notification was canceled by a listener reporting a user dismissal. */
- public static final int REASON_LISTENER_CANCEL = 10;
-
- /** Notification was canceled by a listener reporting a user dismiss all. */
- public static final int REASON_LISTENER_CANCEL_ALL = 11;
-
- /** Notification was canceled because it was a member of a canceled group. */
- public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
-
- /** Notification was canceled because it was an invisible member of a group. */
- public static final int REASON_GROUP_OPTIMIZATION = 13;
-
- /** Notification was canceled by the device administrator suspending the package. */
- public static final int REASON_PACKAGE_SUSPENDED = 14;
-
- /** Notification was canceled by the owning managed profile being turned off. */
- public static final int REASON_PROFILE_TURNED_OFF = 15;
-
- /** Autobundled summary notification was canceled because its group was unbundled */
- public static final int REASON_UNAUTOBUNDLED = 16;
-
- /** Notification was canceled by the user banning the channel. */
- public static final int REASON_CHANNEL_BANNED = 17;
-
- /** Notification was snoozed. */
- public static final int REASON_SNOOZED = 18;
-
- private Handler mHandler;
-
- /** @hide */
- @Override
- public void registerAsSystemService(Context context, ComponentName componentName,
- int currentUser) {
- throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
- }
-
- /** @hide */
- @Override
- public void unregisterAsSystemService() {
- throw new UnsupportedOperationException("the ranker lifecycle is managed by the system.");
- }
-
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- mHandler = new MyHandler(getContext().getMainLooper());
- }
-
- @Override
- public final IBinder onBind(Intent intent) {
- if (mWrapper == null) {
- mWrapper = new NotificationRankingServiceWrapper();
- }
- return mWrapper;
- }
-
- /**
- * A notification was posted by an app. Called before alert.
- *
- * @param sbn the new notification
- * @param importance the initial importance of the notification.
- * @param user true if the initial importance reflects an explicit user preference.
- * @return an adjustment or null to take no action, within 100ms.
- */
- abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
- int importance, boolean user);
-
- /**
- * The visibility of a notification has changed.
- *
- * @param key the notification key
- * @param time milliseconds since midnight, January 1, 1970 UTC.
- * @param visible true if the notification became visible, false if hidden.
- */
- public void onNotificationVisibilityChanged(String key, long time, boolean visible)
- {
- // Do nothing, Override this to collect visibility statistics.
- }
-
- /**
- * The user clicked on a notification.
- *
- * @param key the notification key
- * @param time milliseconds since midnight, January 1, 1970 UTC.
- */
- public void onNotificationClick(String key, long time)
- {
- // Do nothing, Override this to collect click statistics
- }
-
- /**
- * The user clicked on a notification action.
- *
- * @param key the notification key
- * @param time milliseconds since midnight, January 1, 1970 UTC.
- * @param actionIndex the index of the action button that was pressed.
- */
- public void onNotificationActionClick(String key, long time, int actionIndex)
- {
- // Do nothing, Override this to collect action button click statistics
- }
-
- /**
- * A notification was removed.
-
- * @param key the notification key
- * @param time milliseconds since midnight, January 1, 1970 UTC.
- * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
- */
- public void onNotificationRemoved(String key, long time, int reason) {
- // Do nothing, Override this to collect dismissal statistics
- }
-
- /**
- * Updates a notification. N.B. this won’t cause
- * an existing notification to alert, but might allow a future update to
- * this notification to alert.
- *
- * @param adjustment the adjustment with an explanation
- */
- public final void adjustNotification(Adjustment adjustment) {
- if (!isBound()) return;
- try {
- getNotificationInterface().applyAdjustmentFromRankerService(mWrapper, adjustment);
- } catch (android.os.RemoteException ex) {
- Log.v(TAG, "Unable to contact notification manager", ex);
- }
- }
-
- /**
- * Updates existing notifications. Re-ranking won't occur until all adjustments are applied.
- * N.B. this won’t cause an existing notification to alert, but might allow a future update to
- * these notifications to alert.
- *
- * @param adjustments a list of adjustments with explanations
- */
- public final void adjustNotifications(List<Adjustment> adjustments) {
- if (!isBound()) return;
- try {
- getNotificationInterface().applyAdjustmentsFromRankerService(mWrapper, adjustments);
- } catch (android.os.RemoteException ex) {
- Log.v(TAG, "Unable to contact notification manager", ex);
- }
- }
-
- private class NotificationRankingServiceWrapper extends NotificationListenerWrapper {
- @Override
- public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
- int importance, boolean user) {
- StatusBarNotification sbn;
- try {
- sbn = sbnHolder.get();
- } catch (RemoteException e) {
- Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
- return;
- }
-
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = sbn;
- args.argi1 = importance;
- args.argi2 = user ? 1 : 0;
- mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
- args).sendToTarget();
- }
-
- @Override
- public void onNotificationVisibilityChanged(String key, long time, boolean visible) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = key;
- args.arg2 = time;
- args.argi1 = visible ? 1 : 0;
- mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED,
- args).sendToTarget();
- }
-
- @Override
- public void onNotificationClick(String key, long time) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = key;
- args.arg2 = time;
- mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_CLICK,
- args).sendToTarget();
- }
-
- @Override
- public void onNotificationActionClick(String key, long time, int actionIndex) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = key;
- args.arg2 = time;
- args.argi1 = actionIndex;
- mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ACTION_CLICK,
- args).sendToTarget();
- }
-
- @Override
- public void onNotificationRemovedReason(String key, long time, int reason) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = key;
- args.arg2 = time;
- args.argi1 = reason;
- mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED_REASON,
- args).sendToTarget();
- }
- }
-
- private final class MyHandler extends Handler {
- public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
- public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 2;
- public static final int MSG_ON_NOTIFICATION_CLICK = 3;
- public static final int MSG_ON_NOTIFICATION_ACTION_CLICK = 4;
- public static final int MSG_ON_NOTIFICATION_REMOVED_REASON = 5;
-
- public MyHandler(Looper looper) {
- super(looper, null, false);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ON_NOTIFICATION_ENQUEUED: {
- SomeArgs args = (SomeArgs) msg.obj;
- StatusBarNotification sbn = (StatusBarNotification) args.arg1;
- final int importance = args.argi1;
- final boolean user = args.argi2 == 1;
- args.recycle();
- Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
- if (adjustment != null) {
- adjustNotification(adjustment);
- }
- } break;
-
- case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String key = (String) args.arg1;
- final long time = (long) args.arg2;
- final boolean visible = args.argi1 == 1;
- args.recycle();
- onNotificationVisibilityChanged(key, time, visible);
- } break;
-
- case MSG_ON_NOTIFICATION_CLICK: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String key = (String) args.arg1;
- final long time = (long) args.arg2;
- args.recycle();
- onNotificationClick(key, time);
- } break;
-
- case MSG_ON_NOTIFICATION_ACTION_CLICK: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String key = (String) args.arg1;
- final long time = (long) args.arg2;
- final int actionIndex = args.argi1;
- args.recycle();
- onNotificationActionClick(key, time, actionIndex);
- } break;
-
- case MSG_ON_NOTIFICATION_REMOVED_REASON: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String key = (String) args.arg1;
- final long time = (long) args.arg2;
- final int reason = args.argi1;
- args.recycle();
- onNotificationRemoved(key, time, reason);
- } break;
- }
- }
- }
-}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index be0b47c..dfb6b86 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -17,6 +17,7 @@
package android.service.notification;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -42,25 +43,21 @@
private final Notification notification;
private final UserHandle user;
private final long postTime;
+ private final NotificationChannel channel;
private Context mContext; // used for inflation & icon expansion
/** @hide */
- public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
- int initialPid, int score, Notification notification, UserHandle user) {
- this(pkg, opPkg, id, tag, uid, initialPid, score, notification, user,
- System.currentTimeMillis());
- }
-
- /** @hide */
- public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
- int initialPid, Notification notification, UserHandle user, String overrideGroupKey,
- long postTime) {
+ public StatusBarNotification(String pkg, String opPkg, NotificationChannel channel, int id,
+ String tag, int uid, int initialPid, Notification notification, UserHandle user,
+ String overrideGroupKey, long postTime) {
if (pkg == null) throw new NullPointerException();
if (notification == null) throw new NullPointerException();
+ if (channel == null) throw new IllegalArgumentException();
this.pkg = pkg;
this.opPkg = opPkg;
+ this.channel = channel;
this.id = id;
this.tag = tag;
this.uid = uid;
@@ -73,6 +70,7 @@
this.groupKey = groupKey();
}
+ @Deprecated
public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
int initialPid, int score, Notification notification, UserHandle user,
long postTime) {
@@ -90,6 +88,7 @@
this.postTime = postTime;
this.key = key();
this.groupKey = groupKey();
+ this.channel = null;
}
public StatusBarNotification(Parcel in) {
@@ -113,6 +112,7 @@
}
this.key = key();
this.groupKey = groupKey();
+ this.channel = NotificationChannel.CREATOR.createFromParcel(in);
}
private String key() {
@@ -182,6 +182,7 @@
} else {
out.writeInt(0);
}
+ this.channel.writeToParcel(out, flags);
}
public int describeContents() {
@@ -208,14 +209,14 @@
public StatusBarNotification cloneLight() {
final Notification no = new Notification();
this.notification.cloneInto(no, false); // light copy
- return new StatusBarNotification(this.pkg, this.opPkg,
+ return new StatusBarNotification(this.pkg, this.opPkg, this.channel,
this.id, this.tag, this.uid, this.initialPid,
no, this.user, this.overrideGroupKey, this.postTime);
}
@Override
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.opPkg,
+ return new StatusBarNotification(this.pkg, this.opPkg, this.channel,
this.id, this.tag, this.uid, this.initialPid,
this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
}
@@ -335,6 +336,13 @@
}
/**
+ * Returns the channel this notification was posted to.
+ */
+ public NotificationChannel getNotificationChannel() {
+ return channel;
+ }
+
+ /**
* @hide
*/
public Context getPackageContext(Context context) {
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e9bbc2d..12aed25 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -119,6 +119,8 @@
public static final String KEY_CONTENT = "content";
/** @hide */
public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
+ /** @hide */
+ public static final String KEY_AUTO_FILL_CALLBACK = "autoFillCallback";
final Context mContext;
final HandlerCaller mHandlerCaller;
diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java
index b3f2c2a..c0948a6 100644
--- a/core/java/android/text/Editable.java
+++ b/core/java/android/text/Editable.java
@@ -121,8 +121,10 @@
public InputFilter[] getFilters();
/**
- * Factory used by TextView to create new Editables. You can subclass
- * it to provide something other than SpannableStringBuilder.
+ * Factory used by TextView to create new {@link Editable Editables}. You can subclass
+ * it to provide something other than {@link SpannableStringBuilder}.
+ *
+ * @see android.widget.TextView#setEditableFactory(Factory)
*/
public static class Factory {
private static Editable.Factory sInstance = new Editable.Factory();
diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java
index ae5d356..39b78eb 100644
--- a/core/java/android/text/Spannable.java
+++ b/core/java/android/text/Spannable.java
@@ -46,15 +46,17 @@
public void removeSpan(Object what);
/**
- * Factory used by TextView to create new Spannables. You can subclass
- * it to provide something other than SpannableString.
+ * Factory used by TextView to create new {@link Spannable Spannables}. You can subclass
+ * it to provide something other than {@link SpannableString}.
+ *
+ * @see android.widget.TextView#setSpannableFactory(Factory)
*/
public static class Factory {
private static Spannable.Factory sInstance = new Spannable.Factory();
/**
* Returns the standard Spannable Factory.
- */
+ */
public static Spannable.Factory getInstance() {
return sInstance;
}
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 479f493..6e4d78d 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -242,14 +242,20 @@
Transition mTransition;
ViewGroup mSceneRoot;
+ final ViewTreeObserver mViewTreeObserver;
MultiListener(Transition transition, ViewGroup sceneRoot) {
mTransition = transition;
mSceneRoot = sceneRoot;
+ mViewTreeObserver = mSceneRoot.getViewTreeObserver();
}
private void removeListeners() {
- mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (mViewTreeObserver.isAlive()) {
+ mViewTreeObserver.removeOnPreDrawListener(this);
+ } else {
+ mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
mSceneRoot.removeOnAttachStateChangeListener(this);
}
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index f4eb132..1abc10d 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -16,31 +16,78 @@
package android.util;
+import android.annotation.HalfFloat;
+
/**
* <p>Half is a utility class to manipulate half-precision 16-bit
* <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
- * floating point data types (also called fp16 or binary16). A half-precision
- * float is stored in a short data type. A half-precision float can be
- * created from or converted to single-precision floats.</p>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ * To distinguish short values holding half-precision floats from regular short values,
+ * it is recommended to use the <code>@HalfFloat</code> annotation.</p>
*
* <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
* <ul>
* <li>Sign bit: 1 bit</li>
* <li>Exponent width: 5 bits</li>
- * <li>Mantissa: 10 bits</li>
+ * <li>Significand: 10 bits</li>
* </ul>
*
- * <p>The format is laid out thusly:</p>
+ * <p>The format is laid out as follows:</p>
* <pre>
* 1 11111 1111111111
* ^ --^-- -----^----
- * sign | |_______ mantissa
+ * sign | |_______ significand
* |
* -- exponent
* </pre>
*
- * @hide
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ * <tr><th>Range start</th><th>Precision</th></tr>
+ * <tr><td>0</td><td>1 ⁄ 16,777,216</td></tr>
+ * <tr><td>1 ⁄ 16,384</td><td>1 ⁄ 16,777,216</td></tr>
+ * <tr><td>1 ⁄ 8,192</td><td>1 ⁄ 8,388,608</td></tr>
+ * <tr><td>1 ⁄ 4,096</td><td>1 ⁄ 4,194,304</td></tr>
+ * <tr><td>1 ⁄ 2,048</td><td>1 ⁄ 2,097,152</td></tr>
+ * <tr><td>1 ⁄ 1,024</td><td>1 ⁄ 1,048,576</td></tr>
+ * <tr><td>1 ⁄ 512</td><td>1 ⁄ 524,288</td></tr>
+ * <tr><td>1 ⁄ 256</td><td>1 ⁄ 262,144</td></tr>
+ * <tr><td>1 ⁄ 128</td><td>1 ⁄ 131,072</td></tr>
+ * <tr><td>1 ⁄ 64</td><td>1 ⁄ 65,536</td></tr>
+ * <tr><td>1 ⁄ 32</td><td>1 ⁄ 32,768</td></tr>
+ * <tr><td>1 ⁄ 16</td><td>1 ⁄ 16,384</td></tr>
+ * <tr><td>1 ⁄ 8</td><td>1 ⁄ 8,192</td></tr>
+ * <tr><td>1 ⁄ 4</td><td>1 ⁄ 4,096</td></tr>
+ * <tr><td>1 ⁄ 2</td><td>1 ⁄ 2,048</td></tr>
+ * <tr><td>1</td><td>1 ⁄ 1,024</td></tr>
+ * <tr><td>2</td><td>1 ⁄ 512</td></tr>
+ * <tr><td>4</td><td>1 ⁄ 256</td></tr>
+ * <tr><td>8</td><td>1 ⁄ 128</td></tr>
+ * <tr><td>16</td><td>1 ⁄ 64</td></tr>
+ * <tr><td>32</td><td>1 ⁄ 32</td></tr>
+ * <tr><td>64</td><td>1 ⁄ 16</td></tr>
+ * <tr><td>128</td><td>1 ⁄ 8</td></tr>
+ * <tr><td>256</td><td>1 ⁄ 4</td></tr>
+ * <tr><td>512</td><td>1 ⁄ 2</td></tr>
+ * <tr><td>1,024</td><td>1</td></tr>
+ * <tr><td>2,048</td><td>2</td></tr>
+ * <tr><td>4,096</td><td>4</td></tr>
+ * <tr><td>8,192</td><td>8</td></tr>
+ * <tr><td>16,384</td><td>16</td></tr>
+ * <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
*/
+@SuppressWarnings("SimplifiableIfStatement")
public final class Half {
/**
* The number of bits used to represent a half-precision float value.
@@ -51,104 +98,410 @@
* Epsilon is the difference between 1.0 and the next value representable
* by a half-precision floating-point.
*/
- public static final short EPSILON = (short) 0x1400;
- /**
- * Smallest negative value a half-precision float may have.
- */
- public static final short LOWEST_VALUE = (short) 0xfbff;
+ public static final @HalfFloat short EPSILON = (short) 0x1400;
+
/**
* Maximum exponent a finite half-precision float may have.
*/
- public static final short MAX_EXPONENT = 15;
- /**
- * Maximum positive finite value a half-precision float may have.
- */
- public static final short MAX_VALUE = (short) 0x7bff;
+ public static final int MAX_EXPONENT = 15;
/**
* Minimum exponent a normalized half-precision float may have.
*/
- public static final short MIN_EXPONENT = -14;
+ public static final int MIN_EXPONENT = -14;
+
+ /**
+ * Smallest negative value a half-precision float may have.
+ */
+ public static final @HalfFloat short LOWEST_VALUE = (short) 0xfbff;
+ /**
+ * Maximum positive finite value a half-precision float may have.
+ */
+ public static final @HalfFloat short MAX_VALUE = (short) 0x7bff;
/**
* Smallest positive normal value a half-precision float may have.
*/
- public static final short MIN_NORMAL = (short) 0x0400;
+ public static final @HalfFloat short MIN_NORMAL = (short) 0x0400;
/**
* Smallest positive non-zero value a half-precision float may have.
*/
- public static final short MIN_VALUE = (short) 0x0001;
+ public static final @HalfFloat short MIN_VALUE = (short) 0x0001;
/**
* A Not-a-Number representation of a half-precision float.
*/
- public static final short NaN = (short) 0x7e00;
+ public static final @HalfFloat short NaN = (short) 0x7e00;
/**
* Negative infinity of type half-precision float.
*/
- public static final short NEGATIVE_INFINITY = (short) 0xfc00;
+ public static final @HalfFloat short NEGATIVE_INFINITY = (short) 0xfc00;
/**
* Negative 0 of type half-precision float.
*/
- public static final short NEGATIVE_ZERO = (short) 0x8000;
+ public static final @HalfFloat short NEGATIVE_ZERO = (short) 0x8000;
/**
* Positive infinity of type half-precision float.
*/
- public static final short POSITIVE_INFINITY = (short) 0x7c00;
+ public static final @HalfFloat short POSITIVE_INFINITY = (short) 0x7c00;
/**
* Positive 0 of type half-precision float.
*/
- public static final short POSITIVE_ZERO = (short) 0x0000;
+ public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000;
- private static final int FP16_SIGN_SHIFT = 15;
- private static final int FP16_EXPONENT_SHIFT = 10;
- private static final int FP16_EXPONENT_MASK = 0x1f;
- private static final int FP16_MANTISSA_MASK = 0x3ff;
- private static final int FP16_EXPONENT_BIAS = 15;
+ private static final int FP16_SIGN_SHIFT = 15;
+ private static final int FP16_SIGN_MASK = 0x8000;
+ private static final int FP16_EXPONENT_SHIFT = 10;
+ private static final int FP16_EXPONENT_MASK = 0x1f;
+ private static final int FP16_SIGNIFICAND_MASK = 0x3ff;
+ private static final int FP16_EXPONENT_BIAS = 15;
+ private static final int FP16_COMBINED = 0x7fff;
+ private static final int FP16_EXPONENT_MAX = 0x7c00;
- private static final int FP32_SIGN_SHIFT = 31;
- private static final int FP32_EXPONENT_SHIFT = 23;
- private static final int FP32_EXPONENT_MASK = 0xff;
- private static final int FP32_MANTISSA_MASK = 0x7fffff;
- private static final int FP32_EXPONENT_BIAS = 127;
+ private static final int FP32_SIGN_SHIFT = 31;
+ private static final int FP32_EXPONENT_SHIFT = 23;
+ private static final int FP32_EXPONENT_MASK = 0xff;
+ private static final int FP32_SIGNIFICAND_MASK = 0x7fffff;
+ private static final int FP32_EXPONENT_BIAS = 127;
- private static final int FP32_DENORMAL_MAGIC = 126 << 23;
- private static final float FP32_DENORMAL_FLOAT =
- Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
+ private static final int FP32_DENORMAL_MAGIC = 126 << 23;
+ private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
private Half() {
}
/**
+ * Returns the first parameter with the sign of the second parameter.
+ * This method treats NaNs as having a sign.
+ *
+ * @param magnitude A half-precision float value providing the magnitude of the result
+ * @param sign A half-precision float value providing the sign of the result
+ * @return A value with the magnitude of the first parameter and the sign
+ * of the second parameter
+ */
+ public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) {
+ return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED));
+ }
+
+ /**
+ * Returns the absolute value of the specified half-precision float.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is positive zero (see {@link #POSITIVE_ZERO})</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is positive infinity (see {@link #POSITIVE_INFINITY})</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The absolute value of the specified half-precision float
+ */
+ public static @HalfFloat short abs(@HalfFloat short h) {
+ return (short) (h & FP16_COMBINED);
+ }
+
+ /**
+ * Returns the closest integral half-precision float value to the specified
+ * half-precision float value. Special values are handled in the
+ * following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The value of the specified half-precision float rounded to the nearest
+ * half-precision float value
+ */
+ public static @HalfFloat short round(@HalfFloat short h) {
+ int bits = h & 0xffff;
+ int e = bits & 0x7fff;
+ int result = bits;
+
+ if (e < 0x3c00) {
+ result &= FP16_SIGN_MASK;
+ result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0));
+ } else if (e < 0x6400) {
+ e = 25 - (e >> 10);
+ int mask = (1 << e) - 1;
+ result += (1 << (e - 1));
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value
+ */
+ public static @HalfFloat short ceil(@HalfFloat short h) {
+ int bits = h & 0xffff;
+ int e = bits & 0x7fff;
+ int result = bits;
+
+ if (e < 0x3c00) {
+ result &= FP16_SIGN_MASK;
+ result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0));
+ } else if (e < 0x6400) {
+ e = 25 - (e >> 10);
+ int mask = (1 << e) - 1;
+ result += mask & ((bits >> 15) - 1);
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value
+ */
+ public static @HalfFloat short floor(@HalfFloat short h) {
+ int bits = h & 0xffff;
+ int e = bits & 0x7fff;
+ int result = bits;
+
+ if (e < 0x3c00) {
+ result &= FP16_SIGN_MASK;
+ result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
+ } else if (e < 0x6400) {
+ e = 25 - (e >> 10);
+ int mask = (1 << e) - 1;
+ result += mask & -(bits >> 15);
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the truncated half-precision float value of the specified
+ * half-precision float value. Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The truncated half-precision float value of the specified
+ * half-precision float value
+ */
+ public static @HalfFloat short trunc(@HalfFloat short h) {
+ int bits = h & 0xffff;
+ int e = bits & 0x7fff;
+ int result = bits;
+
+ if (e < 0x3c00) {
+ result &= FP16_SIGN_MASK;
+ } else if (e < 0x6400) {
+ e = 25 - (e >> 10);
+ int mask = (1 << e) - 1;
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smaller of two half-precision float values (the value closest
+ * to negative infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ * @return The smaller of the two specified half-precision values
+ */
+ public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+
+ if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
+ return (x & FP16_SIGN_MASK) != 0 ? x : y;
+ }
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns the larger of two half-precision float values (the value closest
+ * to positive infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return The larger of the two specified half-precision values
+ */
+ public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN;
+
+ if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) {
+ return (x & FP16_SIGN_MASK) != 0 ? y : x;
+ }
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than y, false otherwise
+ */
+ public static boolean less(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than or equal to the second half-precision
+ * float value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than or equal to y, false otherwise
+ */
+ public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ */
+ public static boolean greater(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than or equal to the second half-precision float
+ * value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ */
+ public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+ return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+ ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the two half-precision float values are equal.
+ * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+ * and {@link #NEGATIVE_ZERO} are considered equal.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is equal to y, false otherwise
+ */
+ public static boolean equals(@HalfFloat short x, @HalfFloat short y) {
+ if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+ if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false;
+
+ return x == y || ((x | y) & FP16_COMBINED) == 0;
+ }
+
+ /**
* Returns the sign of the specified half-precision float.
*
* @param h A half-precision float value
* @return 1 if the value is positive, -1 if the value is negative
*/
- public static int getSign(short h) {
- return (h >>> FP16_SIGN_SHIFT) == 0 ? 1 : -1;
+ public static int getSign(@HalfFloat short h) {
+ return (h & FP16_SIGN_MASK) == 0 ? 1 : -1;
}
/**
* Returns the unbiased exponent used in the representation of
* the specified half-precision float value. if the value is NaN
* or infinite, this* method returns {@link #MAX_EXPONENT} + 1.
- * If the argument is* 0 or denormal, this method returns
- * {@link #MIN_EXPONENT} - 1.
+ * If the argument is 0 or a subnormal representation, this method
+ * returns {@link #MIN_EXPONENT} - 1.
*
* @param h A half-precision float value
* @return The unbiased exponent of the specified value
*/
- public static int getExponent(short h) {
+ public static int getExponent(@HalfFloat short h) {
return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS;
}
/**
- * Returns the mantissa, or significand, used in the representation
+ * Returns the significand, or mantissa, used in the representation
* of the specified half-precision float value.
*
* @param h A half-precision float value
- * @return The mantissa, or significand, of the specified vlaue
+ * @return The significand, or significand, of the specified vlaue
*/
- public static int getMantissa(short h) {
- return h & FP16_MANTISSA_MASK;
+ public static int getSignificand(@HalfFloat short h) {
+ return h & FP16_SIGNIFICAND_MASK;
}
/**
@@ -159,10 +512,8 @@
* @return true if the value is positive infinity or negative infinity,
* false otherwise
*/
- public static boolean isInfinite(short h) {
- int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (h ) & FP16_MANTISSA_MASK;
- return e == 0x1f && m == 0;
+ public static boolean isInfinite(@HalfFloat short h) {
+ return (h & FP16_COMBINED) == FP16_EXPONENT_MAX;
}
/**
@@ -172,10 +523,22 @@
* @param h A half-precision float value
* @return true if the value is a NaN, false otherwise
*/
- public static boolean isNaN(short h) {
- int e = (h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (h ) & FP16_MANTISSA_MASK;
- return e == 0x1f && m != 0;
+ public static boolean isNaN(@HalfFloat short h) {
+ return (h & FP16_COMBINED) > FP16_EXPONENT_MAX;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value is normalized
+ * (does not have a subnormal representation). If the specified value is
+ * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+ * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+ * number, this method returns false.
+ *
+ * @param h A half-precision float value
+ * @return true if the value is normalized, false otherwise
+ */
+ public static boolean isNormalized(@HalfFloat short h) {
+ return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX;
}
/**
@@ -193,11 +556,11 @@
* @param h The half-precision float value to convert to single-precision
* @return A normalized single-precision float value
*/
- public static float toFloat(short h) {
+ public static float toFloat(@HalfFloat short h) {
int bits = h & 0xffff;
- int s = (bits >>> FP16_SIGN_SHIFT );
+ int s = bits & FP16_SIGN_MASK;
int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (bits ) & FP16_MANTISSA_MASK;
+ int m = (bits ) & FP16_SIGNIFICAND_MASK;
int outE = 0;
int outM = 0;
@@ -218,7 +581,7 @@
}
}
- int out = (s << FP32_SIGN_SHIFT) | (outE << FP32_EXPONENT_SHIFT) | outM;
+ int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
return Float.intBitsToFloat(out);
}
@@ -245,11 +608,11 @@
* @return A half-precision float value
*/
@SuppressWarnings("StatementWithEmptyBody")
- public static short valueOf(float f) {
+ public static @HalfFloat short valueOf(float f) {
int bits = Float.floatToRawIntBits(f);
int s = (bits >>> FP32_SIGN_SHIFT );
int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK;
- int m = (bits ) & FP32_MANTISSA_MASK;
+ int m = (bits ) & FP32_SIGNIFICAND_MASK;
int outE = 0;
int outM = 0;
@@ -278,14 +641,12 @@
// Round to nearest "0.5" up
int out = (outE << FP16_EXPONENT_SHIFT) | outM;
out++;
- out |= (s << FP16_SIGN_SHIFT);
- return (short) out;
+ return (short) (out | (s << FP16_SIGN_SHIFT));
}
}
}
- int out = (s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM;
- return (short) out;
+ return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM);
}
/**
@@ -297,7 +658,7 @@
* @param h A half-precision float value
* @return A string representation of the specified value
*/
- public static String toString(short h) {
+ public static String toString(@HalfFloat short h) {
return Float.toString(toFloat(h));
}
@@ -311,33 +672,33 @@
* <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
* <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
* <li>If the value has a normalized representation, the exponent and
- * mantissa are represented in the string in two fields. The mantissa starts
- * with <code>"0x1."</code> followed by its lowercase hexadecimal
+ * significand are represented in the string in two fields. The significand
+ * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
* representation. Trailing zeroes are removed unless all digits are 0, then
- * a single zero is used. The mantissa representation is followed by the
+ * a single zero is used. The significand representation is followed by the
* exponent, represented by <code>"p"</code>, itself followed by a decimal
* string of the unbiased exponent</li>
- * <li>If the value has a denormal representation, the mantissa starts
+ * <li>If the value has a subnormal representation, the significand starts
* with <code>"0x0."</code> followed by its lowercase hexadecimal
* representation. Trailing zeroes are removed unless all digits are 0, then
- * a single zero is used. The mantissa representation is followed by the
+ * a single zero is used. The significand representation is followed by the
* exponent, represented by <code>"p-14"</code></li>
* </ul>
*
* @param h A half-precision float value
* @return A hexadecimal string representation of the specified value
*/
- public static String toHexString(short h) {
+ public static String toHexString(@HalfFloat short h) {
StringBuilder o = new StringBuilder();
int bits = h & 0xffff;
int s = (bits >>> FP16_SIGN_SHIFT );
int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK;
- int m = (bits ) & FP16_MANTISSA_MASK;
+ int m = (bits ) & FP16_SIGNIFICAND_MASK;
if (e == 0x1f) { // Infinite or NaN
if (m == 0) {
- if (s == 1) o.append('-');
+ if (s != 0) o.append('-');
o.append("Infinity");
} else {
o.append("NaN");
@@ -349,14 +710,14 @@
o.append("0x0.0p0");
} else {
o.append("0x0.");
- String mantissa = Integer.toHexString(m);
- o.append(mantissa.replaceFirst("0{2,}$", ""));
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
o.append("p-14");
}
} else {
o.append("0x1.");
- String mantissa = Integer.toHexString(m);
- o.append(mantissa.replaceFirst("0{2,}$", ""));
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
o.append('p');
o.append(Integer.toString(e - FP16_EXPONENT_BIAS));
}
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index a81eef8..d59be02 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -32,6 +32,11 @@
oneway void setInInteractiveMode(boolean inInteractiveMode);
/**
+ * Notifies the controller that the PIP is currently minimized.
+ */
+ oneway void setIsMinimized(boolean isMinimized);
+
+ /**
* Notifies the controller that the desired snap mode is to the closest edge.
*/
oneway void setSnapToEdge(boolean snapToEdge);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0bb84cc..5012215 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -18,7 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -921,7 +921,7 @@
private static void initSched(Context context, long renderProxy) {
try {
int tid = nGetRenderThreadTid(renderProxy);
- ActivityManagerNative.getDefault().setRenderThread(tid);
+ ActivityManager.getService().setRenderThread(tid);
} catch (Throwable t) {
Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 441f330..02a8521 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6703,6 +6703,11 @@
} else {
structure.setId(id, null, null, null);
}
+
+ // The auto-fill id needs to be unique, but its value doesn't matter, so it's better to
+ // reuse the accessibility id to save space.
+ structure.setAutoFillId(getAccessibilityViewId());
+
structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
if (!hasIdentityMatrix()) {
structure.setTransformation(getMatrix());
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cdd8b6a..1ff8fb0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -26,7 +26,7 @@
import android.Manifest;
import android.animation.LayoutTransition;
import android.annotation.NonNull;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ResourcesManager;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -7084,7 +7084,7 @@
private static int checkCallingPermission(String permission) {
try {
- return ActivityManagerNative.getDefault().checkPermission(
+ return ActivityManager.getService().checkPermission(
permission, Binder.getCallingPid(), Binder.getCallingUid());
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 2e4ba74..e9ff9d0 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -275,4 +275,7 @@
/** @hide */
public abstract Rect getTempRect();
+
+ /** @hide */
+ public abstract void setAutoFillId(int autoFillId);
}
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index ec852e8..85d10f1 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -142,11 +142,17 @@
* @see #getInflatedId()
* @attr ref android.R.styleable#ViewStub_inflatedId
*/
- @android.view.RemotableViewMethod
+ @android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync")
public void setInflatedId(@IdRes int inflatedId) {
mInflatedId = inflatedId;
}
+ /** @hide **/
+ public Runnable setInflatedIdAsync(@IdRes int inflatedId) {
+ mInflatedId = inflatedId;
+ return null;
+ }
+
/**
* Returns the layout resource that will be used by {@link #setVisibility(int)} or
* {@link #inflate()} to replace this StubbedView
@@ -176,11 +182,17 @@
* @see #inflate()
* @attr ref android.R.styleable#ViewStub_layout
*/
- @android.view.RemotableViewMethod
+ @android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync")
public void setLayoutResource(@LayoutRes int layoutResource) {
mLayoutResource = layoutResource;
}
+ /** @hide **/
+ public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) {
+ mLayoutResource = layoutResource;
+ return null;
+ }
+
/**
* Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null}
* to use the default.
@@ -220,7 +232,7 @@
* @see #inflate()
*/
@Override
- @android.view.RemotableViewMethod
+ @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
public void setVisibility(int visibility) {
if (mInflatedViewRef != null) {
View view = mInflatedViewRef.get();
@@ -237,6 +249,43 @@
}
}
+ /** @hide **/
+ public Runnable setVisibilityAsync(int visibility) {
+ if (visibility == VISIBLE || visibility == INVISIBLE) {
+ ViewGroup parent = (ViewGroup) getParent();
+ return new ViewReplaceRunnable(inflateViewNoAdd(parent));
+ } else {
+ return null;
+ }
+ }
+
+ private View inflateViewNoAdd(ViewGroup parent) {
+ final LayoutInflater factory;
+ if (mInflater != null) {
+ factory = mInflater;
+ } else {
+ factory = LayoutInflater.from(mContext);
+ }
+ final View view = factory.inflate(mLayoutResource, parent, false);
+
+ if (mInflatedId != NO_ID) {
+ view.setId(mInflatedId);
+ }
+ return view;
+ }
+
+ private void replaceSelfWithView(View view, ViewGroup parent) {
+ final int index = parent.indexOfChild(this);
+ parent.removeViewInLayout(this);
+
+ final ViewGroup.LayoutParams layoutParams = getLayoutParams();
+ if (layoutParams != null) {
+ parent.addView(view, index, layoutParams);
+ } else {
+ parent.addView(view, index);
+ }
+ }
+
/**
* Inflates the layout resource identified by {@link #getLayoutResource()}
* and replaces this StubbedView in its parent by the inflated layout resource.
@@ -250,31 +299,10 @@
if (viewParent != null && viewParent instanceof ViewGroup) {
if (mLayoutResource != 0) {
final ViewGroup parent = (ViewGroup) viewParent;
- final LayoutInflater factory;
- if (mInflater != null) {
- factory = mInflater;
- } else {
- factory = LayoutInflater.from(mContext);
- }
- final View view = factory.inflate(mLayoutResource, parent,
- false);
+ final View view = inflateViewNoAdd(parent);
+ replaceSelfWithView(view, parent);
- if (mInflatedId != NO_ID) {
- view.setId(mInflatedId);
- }
-
- final int index = parent.indexOfChild(this);
- parent.removeViewInLayout(this);
-
- final ViewGroup.LayoutParams layoutParams = getLayoutParams();
- if (layoutParams != null) {
- parent.addView(view, index, layoutParams);
- } else {
- parent.addView(view, index);
- }
-
- mInflatedViewRef = new WeakReference<View>(view);
-
+ mInflatedViewRef = new WeakReference<>(view);
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
@@ -317,4 +345,18 @@
*/
void onInflate(ViewStub stub, View inflated);
}
+
+ /** @hide **/
+ public class ViewReplaceRunnable implements Runnable {
+ public final View view;
+
+ ViewReplaceRunnable(View view) {
+ this.view = view;
+ }
+
+ @Override
+ public void run() {
+ replaceSelfWithView(view, (ViewGroup) getParent());
+ }
+ }
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 8a9bb33..82379c4 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -509,6 +509,11 @@
* Notifies window manager that {@link #isShowingDreamLw} has changed.
*/
void notifyShowingDreamChanged();
+
+ /**
+ * Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
+ */
+ void notifyKeyguardTrustedChanged();
}
public interface PointerEventListener {
@@ -667,7 +672,7 @@
* button bar.
*/
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
- int uiMode);
+ int uiMode, int displayId);
/**
* Return the display height available after excluding any screen
@@ -675,7 +680,7 @@
* button bar.
*/
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
- int uiMode);
+ int uiMode, int displayId);
/**
* Return the available screen width that we should report for the
@@ -684,7 +689,7 @@
* that to account for more transient decoration like a status bar.
*/
public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation,
- int uiMode);
+ int uiMode, int displayId);
/**
* Return the available screen height that we should report for the
@@ -693,7 +698,7 @@
* that to account for more transient decoration like a status bar.
*/
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation,
- int uiMode);
+ int uiMode, int displayId);
/**
* Return whether the given window can become the Keyguard window. Typically returns true for
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 8038089..2f12e9b 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -34,6 +34,54 @@
*/
public class EditorInfo implements InputType, Parcelable {
/**
+ * Masks for {@link inputType}
+ *
+ * <pre>
+ * |-------|-------|-------|-------|
+ * 1111 TYPE_MASK_CLASS
+ * 11111111 TYPE_MASK_VARIATION
+ * 111111111111 TYPE_MASK_FLAGS
+ * |-------|-------|-------|-------|
+ * TYPE_NULL
+ * |-------|-------|-------|-------|
+ * 1 TYPE_CLASS_TEXT
+ * 1 TYPE_TEXT_VARIATION_URI
+ * 1 TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ * 11 TYPE_TEXT_VARIATION_EMAIL_SUBJECT
+ * 1 TYPE_TEXT_VARIATION_SHORT_MESSAGE
+ * 1 1 TYPE_TEXT_VARIATION_LONG_MESSAGE
+ * 11 TYPE_TEXT_VARIATION_PERSON_NAME
+ * 111 TYPE_TEXT_VARIATION_POSTAL_ADDRESS
+ * 1 TYPE_TEXT_VARIATION_PASSWORD
+ * 1 1 TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+ * 1 1 TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+ * 1 11 TYPE_TEXT_VARIATION_FILTER
+ * 11 TYPE_TEXT_VARIATION_PHONETIC
+ * 11 1 TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS
+ * 111 TYPE_TEXT_VARIATION_WEB_PASSWORD
+ * 1 TYPE_TEXT_FLAG_CAP_CHARACTERS
+ * 1 TYPE_TEXT_FLAG_CAP_WORDS
+ * 1 TYPE_TEXT_FLAG_CAP_SENTENCES
+ * 1 TYPE_TEXT_FLAG_AUTO_CORRECT
+ * 1 TYPE_TEXT_FLAG_AUTO_COMPLETE
+ * 1 TYPE_TEXT_FLAG_MULTI_LINE
+ * 1 TYPE_TEXT_FLAG_IME_MULTI_LINE
+ * 1 TYPE_TEXT_FLAG_NO_SUGGESTIONS
+ * |-------|-------|-------|-------|
+ * 1 TYPE_CLASS_NUMBER
+ * 1 TYPE_NUMBER_VARIATION_PASSWORD
+ * 1 TYPE_NUMBER_FLAG_SIGNED
+ * 1 TYPE_NUMBER_FLAG_DECIMAL
+ * |-------|-------|-------|-------|
+ * 11 TYPE_CLASS_PHONE
+ * |-------|-------|-------|-------|
+ * 1 TYPE_CLASS_DATETIME
+ * 1 TYPE_DATETIME_VARIATION_DATE
+ * 1 TYPE_DATETIME_VARIATION_TIME
+ * |-------|-------|-------|-------|</pre>
+ */
+
+ /**
* The content type of the text box, whose bits are defined by
* {@link InputType}.
*
@@ -107,6 +155,26 @@
public static final int IME_ACTION_PREVIOUS = 0x00000007;
/**
+ * Flag of {@link #imeOptions}: used to request that the IME does not update any personalized
+ * data such as typing history and personalized language model based on what the user typed on
+ * this text editing object. Typical use cases are:
+ * <ul>
+ * <li>When the application is in a special mode, where user's activities are expected to be
+ * not recorded in the application's history. Some web browsers and chat applications may
+ * have this kind of modes.</li>
+ * <li>When storing typing history does not make much sense. Specifying this flag in typing
+ * games may help to avoid typing history from being filled up with words that the user is
+ * less likely to type in their daily life. Another example is that when the application
+ * already knows that the expected input is not a valid word (e.g. a promotion code that is
+ * not a valid word in any natural language).</li>
+ * </ul>
+ *
+ * <p>Applications need to be aware that the flag is not a guarantee, and some IMEs may not
+ * respect it.</p>
+ */
+ public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000;
+
+ /**
* Flag of {@link #imeOptions}: used to request that the IME never go
* into fullscreen mode.
* By default, IMEs may go into full screen mode when they think
@@ -208,6 +276,32 @@
public static final int IME_NULL = 0x00000000;
/**
+ * Masks for {@link imeOptions}
+ *
+ * <pre>
+ * |-------|-------|-------|-------|
+ * 1111 IME_MASK_ACTION
+ * |-------|-------|-------|-------|
+ * IME_ACTION_UNSPECIFIED
+ * 1 IME_ACTION_NONE
+ * 1 IME_ACTION_GO
+ * 11 IME_ACTION_SEARCH
+ * 1 IME_ACTION_SEND
+ * 1 1 IME_ACTION_NEXT
+ * 11 IME_ACTION_DONE
+ * 111 IME_ACTION_PREVIOUS
+ * 1 IME_FLAG_NO_PERSONALIZED_LEARNING
+ * 1 IME_FLAG_NO_FULLSCREEN
+ * 1 IME_FLAG_NAVIGATE_PREVIOUS
+ * 1 IME_FLAG_NAVIGATE_NEXT
+ * 1 IME_FLAG_NO_EXTRACT_UI
+ * 1 IME_FLAG_NO_ACCESSORY_ACTION
+ * 1 IME_FLAG_NO_ENTER_ACTION
+ * 1 IME_FLAG_FORCE_ASCII
+ * |-------|-------|-------|-------|</pre>
+ */
+
+ /**
* Extended type information for the editor, to help the IME better
* integrate with it.
*/
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
index b39705e..7104a28 100644
--- a/core/java/android/view/inputmethod/InputContentInfo.java
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -18,11 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.ClipDescription;
+import android.content.ContentProvider;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.UserHandle;
import com.android.internal.inputmethod.IInputContentUriToken;
@@ -33,8 +36,24 @@
*/
public final class InputContentInfo implements Parcelable {
+ /**
+ * The content URI that may or may not have a user ID embedded by
+ * {@link ContentProvider#maybeAddUserId(Uri, int)}. This always preserves the exact value
+ * specified to a constructor. In other words, if it had user ID embedded when it was passed
+ * to the constructor, it still has the same user ID no matter if it is valid or not.
+ */
@NonNull
private final Uri mContentUri;
+ /**
+ * The user ID to which {@link #mContentUri} belongs to. If {@link #mContentUri} already
+ * embedded the user ID when it was specified then this fields has the same user ID. Otherwise
+ * the user ID is determined based on the process ID when the constructor is called.
+ *
+ * <p>CAUTION: If you received {@link InputContentInfo} from a different process, there is no
+ * guarantee that this value is correct and valid. Never use this for any security purpose</p>
+ */
+ @UserIdInt
+ private final int mContentUriOwnerUserId;
@NonNull
private final ClipDescription mDescription;
@Nullable
@@ -73,6 +92,8 @@
@Nullable Uri linkUri) {
validateInternal(contentUri, description, linkUri, true /* throwException */);
mContentUri = contentUri;
+ mContentUriOwnerUserId =
+ ContentProvider.getUserIdFromUri(mContentUri, UserHandle.myUserId());
mDescription = description;
mLinkUri = linkUri;
}
@@ -139,7 +160,14 @@
* @return Content URI with which the content can be obtained.
*/
@NonNull
- public Uri getContentUri() { return mContentUri; }
+ public Uri getContentUri() {
+ // Fix up the content URI when and only when the caller's user ID does not match the owner's
+ // user ID.
+ if (mContentUriOwnerUserId != UserHandle.myUserId()) {
+ return ContentProvider.maybeAddUserId(mContentUri, mContentUriOwnerUserId);
+ }
+ return mContentUri;
+ }
/**
* @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
@@ -203,6 +231,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
Uri.writeToParcel(dest, mContentUri);
+ dest.writeInt(mContentUriOwnerUserId);
mDescription.writeToParcel(dest, flags);
Uri.writeToParcel(dest, mLinkUri);
if (mUriToken != null) {
@@ -215,6 +244,7 @@
private InputContentInfo(@NonNull Parcel source) {
mContentUri = Uri.CREATOR.createFromParcel(source);
+ mContentUriOwnerUserId = source.readInt();
mDescription = ClipDescription.CREATOR.createFromParcel(source);
mLinkUri = Uri.CREATOR.createFromParcel(source);
if (source.readInt() == 1) {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index f4ea90b..c147895 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -17,8 +17,8 @@
package android.webkit;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
@@ -292,7 +292,7 @@
// killed if the package info goes out-of-date.
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()");
try {
- ActivityManagerNative.getDefault().addPackageDependency(
+ ActivityManager.getService().addPackageDependency(
response.packageInfo.packageName);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 9d228cf..bbc50da 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -312,10 +312,10 @@
}
/**
- * Control whether methods that change the list ({@link #add},
- * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
- * {@link #notifyDataSetChanged}. If set to false, caller must
- * manually call notifyDataSetChanged() to have the changes
+ * Control whether methods that change the list ({@link #add}, {@link #addAll(Collection)},
+ * {@link #addAll(Object[])}, {@link #insert}, {@link #remove}, {@link #clear},
+ * {@link #sort(Comparator)}) automatically call {@link #notifyDataSetChanged}. If set to
+ * false, caller must manually call notifyDataSetChanged() to have the changes
* reflected in the attached view.
*
* The default is true, and calling notifyDataSetChanged()
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index b2a77d0..a9268d4 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -58,6 +58,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.widget.AdapterView.OnItemClickListener;
import com.android.internal.R;
@@ -403,6 +404,7 @@
// Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache
mBitmapCache = new BitmapCache();
setBitmapCache(mBitmapCache);
+ recalculateMemoryUsage();
}
private class SetEmptyView extends Action {
@@ -1456,6 +1458,13 @@
if (endAction == null) {
return ACTION_NOOP;
} else {
+ // Special case view stub
+ if (endAction instanceof ViewStub.ViewReplaceRunnable) {
+ root.createTree();
+ // Replace child tree
+ root.findViewTreeById(viewId).replaceView(
+ ((ViewStub.ViewReplaceRunnable) endAction).view);
+ }
return new RunnableAction(endAction);
}
}
@@ -1581,16 +1590,26 @@
if ((target == null) || !(target.mRoot instanceof ViewGroup)) {
return ACTION_NOOP;
}
+ final ViewGroup targetVg = (ViewGroup) target.mRoot;
if (nestedViews == null) {
// Clear all children when nested views omitted
target.mChildren = null;
- return this;
+ return new RuntimeAction() {
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
+ throws ActionException {
+ targetVg.removeAllViews();
+ }
+ };
} else {
// Inflate nested views and perform all the async tasks for the child remoteView.
final Context context = root.mRoot.getContext();
final AsyncApplyTask task = nestedViews.getAsyncApplyTask(
- context, (ViewGroup) target.mRoot, null, handler);
+ context, targetVg, null, handler);
final ViewTree tree = task.doInBackground();
+ if (tree == null) {
+ throw new ActionException(task.mError);
+ }
// Update the global view tree, so that next call to findViewTreeById
// goes through the subtree as well.
@@ -1600,10 +1619,8 @@
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException {
- // This view will exist as we have already made sure
- final ViewGroup target = (ViewGroup) root.findViewById(viewId);
task.onPostExecute(tree);
- target.addView(task.mResult);
+ targetVg.addView(task.mResult);
}
};
}
@@ -2101,26 +2118,8 @@
return mMemoryUsage;
}
- @SuppressWarnings("deprecation")
public void addBitmapMemory(Bitmap b) {
- final Bitmap.Config c = b.getConfig();
- // If we don't know, be pessimistic and assume 4
- int bpp = 4;
- if (c != null) {
- switch (c) {
- case ALPHA_8:
- bpp = 1;
- break;
- case RGB_565:
- case ARGB_4444:
- bpp = 2;
- break;
- case ARGB_8888:
- bpp = 4;
- break;
- }
- }
- increment(b.getWidth() * b.getHeight() * bpp);
+ increment(b.getAllocationByteCount());
}
int mMemoryUsage;
@@ -3360,7 +3359,7 @@
int count = mRV.mActions.size();
mActions = new Action[count];
for (int i = 0; i < count && !isCancelled(); i++) {
- // TODO: check if isCanclled in nested views.
+ // TODO: check if isCancelled in nested views.
mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler);
}
} else {
@@ -3629,7 +3628,7 @@
* and can be searched.
*/
private static class ViewTree {
- private final View mRoot;
+ private View mRoot;
private ArrayList<ViewTree> mChildren;
@@ -3643,7 +3642,7 @@
}
mChildren = new ArrayList<>();
- if (mRoot instanceof ViewGroup && mRoot.isRootNamespace()) {
+ if (mRoot instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) mRoot;
int count = vg.getChildCount();
for (int i = 0; i < count; i++) {
@@ -3668,6 +3667,12 @@
return null;
}
+ public void replaceView(View v) {
+ mRoot = v;
+ mChildren = null;
+ createTree();
+ }
+
public View findViewById(int id) {
if (mChildren == null) {
return mRoot.findViewById(id);
@@ -3685,6 +3690,12 @@
}
private void addViewChild(View v) {
+ // ViewTree only contains Views which can be found using findViewById.
+ // If isRootNamespace is true, this view is skipped.
+ // @see ViewGroup#findViewTraversal(int)
+ if (v.isRootNamespace()) {
+ return;
+ }
final ViewTree target;
// If the view has a valid id, i.e., if can be found using findViewById, add it to the
@@ -3697,7 +3708,7 @@
target = this;
}
- if (v instanceof ViewGroup && v.isRootNamespace()) {
+ if (v instanceof ViewGroup) {
if (target.mChildren == null) {
target.mChildren = new ArrayList<>();
ViewGroup vg = (ViewGroup) v;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 73af755..5426a37 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1683,12 +1683,13 @@
}
/**
- * Return the text the TextView is displaying. If setText() was called with
- * an argument of BufferType.SPANNABLE or BufferType.EDITABLE, you can cast
+ * Return the text that TextView is displaying. If {@link #setText(CharSequence)} was called
+ * with an argument of {@link android.widget.TextView.BufferType#SPANNABLE BufferType.SPANNABLE}
+ * or {@link android.widget.TextView.BufferType#EDITABLE BufferType.EDITABLE}, you can cast
* the return value from this method to Spannable or Editable, respectively.
- *
- * Note: The content of the return value should not be modified. If you want
- * a modifiable one, you should make your own copy first.
+ * <p/>
+ * The content of the return value should not be modified. If you want a modifiable one, you
+ * should make your own copy first.
*
* @attr ref android.R.styleable#TextView_text
*/
@@ -1705,8 +1706,8 @@
}
/**
- * Return the text the TextView is displaying as an Editable object. If
- * the text is not editable, null is returned.
+ * Return the text that TextView is displaying as an Editable object. If the text is not
+ * editable, null is returned.
*
* @see #getText
*/
@@ -4148,18 +4149,26 @@
}
/**
- * Convenience method: Append the specified text to the TextView's
- * display buffer, upgrading it to BufferType.EDITABLE if it was
- * not already editable.
+ * Convenience method to append the specified text to the TextView's
+ * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
+ * if it was not already editable.
+ *
+ * @param text text to be appended to the already displayed text
*/
public final void append(CharSequence text) {
append(text, 0, text.length());
}
/**
- * Convenience method: Append the specified text slice to the TextView's
- * display buffer, upgrading it to BufferType.EDITABLE if it was
- * not already editable.
+ * Convenience method to append the specified text slice to the TextView's
+ * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
+ * if it was not already editable.
+ *
+ * @param text text to be appended to the already displayed text
+ * @param start the index of the first character in the {@code text}
+ * @param end the index of the character following the last character in the {@code text}
+ *
+ * @see Appendable#append(CharSequence, int, int)
*/
public void append(CharSequence text, int start, int end) {
if (!(mText instanceof Editable)) {
@@ -4403,7 +4412,12 @@
///////////////////////////////////////////////////////////////////////////
/**
- * Sets the Factory used to create new Editables.
+ * Sets the Factory used to create new {@link Editable Editables}.
+ *
+ * @param factory {@link android.text.Editable.Factory Editable.Factory} to be used
+ *
+ * @see android.text.Editable.Factory
+ * @see android.widget.TextView.BufferType#EDITABLE
*/
public final void setEditableFactory(Editable.Factory factory) {
mEditableFactory = factory;
@@ -4411,7 +4425,12 @@
}
/**
- * Sets the Factory used to create new Spannables.
+ * Sets the Factory used to create new {@link Spannable Spannables}.
+ *
+ * @param factory {@link android.text.Spannable.Factory Spannable.Factory} to be used
+ *
+ * @see android.text.Spannable.Factory
+ * @see android.widget.TextView.BufferType#SPANNABLE
*/
public final void setSpannableFactory(Spannable.Factory factory) {
mSpannableFactory = factory;
@@ -4419,13 +4438,20 @@
}
/**
- * Sets the string value of the TextView. TextView <em>does not</em> accept
+ * Sets the text to be displayed. TextView <em>does not</em> accept
* HTML-like formatting, which you can do with text strings in XML resource files.
* To style your strings, attach android.text.style.* objects to a
- * {@link android.text.SpannableString SpannableString}, or see the
+ * {@link android.text.SpannableString}, or see the
* <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">
* Available Resource Types</a> documentation for an example of setting
* formatted text in the XML resource file.
+ * <p/>
+ * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+ * intermediate {@link Spannable Spannables}. Likewise it will use
+ * {@link android.text.Editable.Factory} to create final or intermediate
+ * {@link Editable Editables}.
+ *
+ * @param text text to be displayed
*
* @attr ref android.R.styleable#TextView_text
*/
@@ -4435,10 +4461,16 @@
}
/**
- * Like {@link #setText(CharSequence)},
- * except that the cursor position (if any) is retained in the new text.
+ * Sets the text to be displayed but retains the cursor position. Same as
+ * {@link #setText(CharSequence)} except that the cursor position (if any) is retained in the
+ * new text.
+ * <p/>
+ * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+ * intermediate {@link Spannable Spannables}. Likewise it will use
+ * {@link android.text.Editable.Factory} to create final or intermediate
+ * {@link Editable Editables}.
*
- * @param text The new text to place in the text view.
+ * @param text text to be displayed
*
* @see #setText(CharSequence)
*/
@@ -4448,9 +4480,21 @@
}
/**
- * Sets the text that this TextView is to display (see
- * {@link #setText(CharSequence)}) and also sets whether it is stored
- * in a styleable/spannable buffer and whether it is editable.
+ * Sets the text to be displayed and the {@link android.widget.TextView.BufferType}.
+ * <p/>
+ * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+ * intermediate {@link Spannable Spannables}. Likewise it will use
+ * {@link android.text.Editable.Factory} to create final or intermediate
+ * {@link Editable Editables}.
+ *
+ * @param text text to be displayed
+ * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+ * stored as a static text, styleable/spannable text, or editable text
+ *
+ * @see #setText(CharSequence)
+ * @see android.widget.TextView.BufferType
+ * @see #setSpannableFactory(Spannable.Factory)
+ * @see #setEditableFactory(Editable.Factory)
*
* @attr ref android.R.styleable#TextView_text
* @attr ref android.R.styleable#TextView_bufferType
@@ -4617,10 +4661,14 @@
/**
* Sets the TextView to display the specified slice of the specified
- * char array. You must promise that you will not change the contents
+ * char array. You must promise that you will not change the contents
* of the array except for right before another call to setText(),
* since the TextView has no way to know that the text
* has changed and that it needs to invalidate and re-layout.
+ *
+ * @param text char array to be displayed
+ * @param start start index in the char array
+ * @param len length of char count after {@code start}
*/
public final void setText(char[] text, int start, int len) {
int oldlen = 0;
@@ -4651,8 +4699,19 @@
}
/**
- * Like {@link #setText(CharSequence, android.widget.TextView.BufferType)},
- * except that the cursor position (if any) is retained in the new text.
+ * Sets the text to be displayed and the {@link android.widget.TextView.BufferType} but retains
+ * the cursor position. Same as
+ * {@link #setText(CharSequence, android.widget.TextView.BufferType)} except that the cursor
+ * position (if any) is retained in the new text.
+ * <p/>
+ * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+ * intermediate {@link Spannable Spannables}. Likewise it will use
+ * {@link android.text.Editable.Factory} to create final or intermediate
+ * {@link Editable Editables}.
+ *
+ * @param text text to be displayed
+ * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+ * stored as a static text, styleable/spannable text, or editable text
*
* @see #setText(CharSequence, android.widget.TextView.BufferType)
*/
@@ -4672,11 +4731,42 @@
}
}
+ /**
+ * Sets the text to be displayed using a string resource identifier.
+ *
+ * @param resid the resource identifier of the string resource to be displayed
+ *
+ * @see #setText(CharSequence)
+ *
+ * @attr ref android.R.styleable#TextView_text
+ */
@android.view.RemotableViewMethod
public final void setText(@StringRes int resid) {
setText(getContext().getResources().getText(resid));
}
+ /**
+ * Sets the text to be displayed using a string resource identifier and the
+ * {@link android.widget.TextView.BufferType}.
+ * <p/>
+ * When required, TextView will use {@link android.text.Spannable.Factory} to create final or
+ * intermediate {@link Spannable Spannables}. Likewise it will use
+ * {@link android.text.Editable.Factory} to create final or intermediate
+ * {@link Editable Editables}.
+ *
+ * @param resid the resource identifier of the string resource to be displayed
+ * @param type a {@link android.widget.TextView.BufferType} which defines whether the text is
+ * stored as a static text, styleable/spannable text, or editable text
+ *
+ * @see #setText(int)
+ * @see #setText(CharSequence)
+ * @see android.widget.TextView.BufferType
+ * @see #setSpannableFactory(Spannable.Factory)
+ * @see #setEditableFactory(Editable.Factory)
+ *
+ * @attr ref android.R.styleable#TextView_text
+ * @attr ref android.R.styleable#TextView_bufferType
+ */
public final void setText(@StringRes int resid, BufferType type) {
setText(getContext().getResources().getText(resid), type);
}
@@ -5110,7 +5200,7 @@
* Set the extra input data of the text, which is the
* {@link EditorInfo#extras TextBoxAttribute.extras}
* Bundle that will be filled in when creating an input connection. The
- * given integer is the resource ID of an XML resource holding an
+ * given integer is the resource identifier of an XML resource holding an
* {@link android.R.styleable#InputExtras <input-extras>} XML tree.
*
* @see #getInputExtras(boolean)
@@ -8832,8 +8922,12 @@
}
}
+ /**
+ * Type of the text buffer that defines the characteristics of the text such as static,
+ * styleable, or editable.
+ */
public enum BufferType {
- NORMAL, SPANNABLE, EDITABLE,
+ NORMAL, SPANNABLE, EDITABLE
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3b6073a..d8f7907 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -70,7 +70,7 @@
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.TargetInfo;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.google.android.collect.Lists;
import java.io.File;
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index 83ad9dc..459071b 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -19,7 +19,7 @@
import com.android.internal.R;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
@@ -122,7 +122,7 @@
private OnClickListener mSwitchOldListener = new OnClickListener() {
public void onClick(View v) {
try {
- ActivityManagerNative.getDefault().moveTaskToFront(mCurTask, 0, null);
+ ActivityManager.getService().moveTaskToFront(mCurTask, 0, null);
} catch (RemoteException e) {
}
finish();
@@ -132,7 +132,7 @@
private OnClickListener mSwitchNewListener = new OnClickListener() {
public void onClick(View v) {
try {
- ActivityManagerNative.getDefault().finishHeavyWeightApp();
+ ActivityManager.getService().finishHeavyWeightApp();
} catch (RemoteException e) {
}
try {
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 015e60d..0b27c60 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -19,7 +19,7 @@
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.admin.DevicePolicyManager;
@@ -110,9 +110,9 @@
int launchedFromUid = -1;
String launchedFromPackage = "?";
try {
- launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+ launchedFromUid = ActivityManager.getService().getLaunchedFromUid(
getActivityToken());
- launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+ launchedFromPackage = ActivityManager.getService().getLaunchedFromPackage(
getActivityToken());
} catch (RemoteException ignored) {
}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 472f583..9936ed5 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -18,7 +18,7 @@
import com.android.internal.R;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.ListFragment;
import android.app.backup.BackupManager;
@@ -269,7 +269,7 @@
*/
public static void updateLocales(LocaleList locales) {
try {
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
final Configuration config = am.getConfiguration();
config.setLocales(locales);
@@ -290,7 +290,7 @@
*/
public static LocaleList getLocales() {
try {
- return ActivityManagerNative.getDefault()
+ return ActivityManager.getService()
.getConfiguration().getLocales();
} catch (RemoteException e) {
// If something went wrong
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1e26c92..dd8ef18 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -35,7 +35,6 @@
import com.android.internal.content.PackageMonitor;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
@@ -71,7 +70,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.widget.ResolverDrawerLayout;
import java.util.ArrayList;
@@ -245,7 +244,7 @@
setProfileSwitchMessageId(intent.getContentUserHint());
try {
- mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+ mLaunchedFromUid = ActivityManager.getService().getLaunchedFromUid(
getActivityToken());
} catch (RemoteException e) {
mLaunchedFromUid = -1;
@@ -864,7 +863,7 @@
} catch (RuntimeException e) {
String launchedFromPackage;
try {
- launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+ launchedFromPackage = ActivityManager.getService().getLaunchedFromPackage(
getActivityToken());
} catch (RemoteException e2) {
launchedFromPackage = "??";
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 4e3c3fc..a3134b3b 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -29,7 +29,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
@@ -53,7 +53,7 @@
/**
* Constants used internally between the PackageManager
* and media container service transports.
- * Some utility methods to invoke MountService api.
+ * Some utility methods to invoke StorageManagerService api.
*/
public class PackageHelper {
public static final int RECOMMEND_INSTALL_INTERNAL = 1;
@@ -74,13 +74,13 @@
public static final int APP_INSTALL_INTERNAL = 1;
public static final int APP_INSTALL_EXTERNAL = 2;
- public static IMountService getMountService() throws RemoteException {
+ public static IStorageManager getStorageManager() throws RemoteException {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
- return IMountService.Stub.asInterface(service);
+ return IStorageManager.Stub.asInterface(service);
} else {
- Log.e(TAG, "Can't get mount service");
- throw new RemoteException("Could not contact mount service");
+ Log.e(TAG, "Can't get storagemanager service");
+ throw new RemoteException("Could not contact storagemanager service");
}
}
@@ -89,23 +89,23 @@
// Round up to nearest MB, plus another MB for filesystem overhead
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
try {
- IMountService mountService = getMountService();
+ IStorageManager storageManager = getStorageManager();
if (localLOGV)
Log.i(TAG, "Size of container " + sizeMb + " MB");
- int rc = mountService.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid,
+ int rc = storageManager.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid,
isExternal);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to create secure container " + cid);
return null;
}
- String cachePath = mountService.getSecureContainerPath(cid);
+ String cachePath = storageManager.getSecureContainerPath(cid);
if (localLOGV) Log.i(TAG, "Created secure container " + cid +
" at " + cachePath);
return cachePath;
} catch (RemoteException e) {
- Log.e(TAG, "MountService running?");
+ Log.e(TAG, "StorageManagerService running?");
}
return null;
}
@@ -114,13 +114,13 @@
// Round up to nearest MB, plus another MB for filesystem overhead
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
try {
- IMountService mountService = getMountService();
- int rc = mountService.resizeSecureContainer(cid, sizeMb, sdEncKey);
+ IStorageManager storageManager = getStorageManager();
+ int rc = storageManager.resizeSecureContainer(cid, sizeMb, sdEncKey);
if (rc == StorageResultCode.OperationSucceeded) {
return true;
}
} catch (RemoteException e) {
- Log.e(TAG, "MountService running?");
+ Log.e(TAG, "StorageManagerService running?");
}
Log.e(TAG, "Failed to create secure container " + cid);
return false;
@@ -132,35 +132,35 @@
public static String mountSdDir(String cid, String key, int ownerUid, boolean readOnly) {
try {
- int rc = getMountService().mountSecureContainer(cid, key, ownerUid, readOnly);
+ int rc = getStorageManager().mountSecureContainer(cid, key, ownerUid, readOnly);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
return null;
}
- return getMountService().getSecureContainerPath(cid);
+ return getStorageManager().getSecureContainerPath(cid);
} catch (RemoteException e) {
- Log.e(TAG, "MountService running?");
+ Log.e(TAG, "StorageManagerService running?");
}
return null;
}
public static boolean unMountSdDir(String cid) {
try {
- int rc = getMountService().unmountSecureContainer(cid, true);
+ int rc = getStorageManager().unmountSecureContainer(cid, true);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
return false;
}
return true;
} catch (RemoteException e) {
- Log.e(TAG, "MountService running?");
+ Log.e(TAG, "StorageManagerService running?");
}
return false;
}
public static boolean renameSdDir(String oldId, String newId) {
try {
- int rc = getMountService().renameSecureContainer(oldId, newId);
+ int rc = getStorageManager().renameSecureContainer(oldId, newId);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to rename " + oldId + " to " +
newId + "with rc " + rc);
@@ -176,7 +176,7 @@
public static String getSdDir(String cid) {
try {
- return getMountService().getSecureContainerPath(cid);
+ return getStorageManager().getSecureContainerPath(cid);
} catch (RemoteException e) {
Log.e(TAG, "Failed to get container path for " + cid +
" with exception " + e);
@@ -186,7 +186,7 @@
public static String getSdFilesystem(String cid) {
try {
- return getMountService().getSecureContainerFilesystemPath(cid);
+ return getStorageManager().getSecureContainerFilesystemPath(cid);
} catch (RemoteException e) {
Log.e(TAG, "Failed to get container path for " + cid +
" with exception " + e);
@@ -196,7 +196,7 @@
public static boolean finalizeSdDir(String cid) {
try {
- int rc = getMountService().finalizeSecureContainer(cid);
+ int rc = getStorageManager().finalizeSecureContainer(cid);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to finalize container " + cid);
return false;
@@ -212,7 +212,7 @@
public static boolean destroySdDir(String cid) {
try {
if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid);
- int rc = getMountService().destroySecureContainer(cid, true);
+ int rc = getStorageManager().destroySecureContainer(cid, true);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to destroy container " + cid);
return false;
@@ -227,7 +227,7 @@
public static String[] getSecureContainerList() {
try {
- return getMountService().getSecureContainerList();
+ return getStorageManager().getSecureContainerList();
} catch (RemoteException e) {
Log.e(TAG, "Failed to get secure container list with exception" +
e);
@@ -237,7 +237,7 @@
public static boolean isContainerMounted(String cid) {
try {
- return getMountService().isSecureContainerMounted(cid);
+ return getStorageManager().isSecureContainerMounted(cid);
} catch (RemoteException e) {
Log.e(TAG, "Failed to find out if container " + cid + " mounted");
}
@@ -325,7 +325,7 @@
public static boolean fixSdPermissions(String cid, int gid, String filename) {
try {
- int rc = getMountService().fixPermissionsSecureContainer(cid, gid, filename);
+ int rc = getStorageManager().fixPermissionsSecureContainer(cid, gid, filename);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to fixperms container " + cid);
return false;
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index ef725da..a94f308 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -19,7 +19,7 @@
import android.os.Build;
import android.view.View;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Log all the things.
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
new file mode 100644
index 0000000..b392186
--- /dev/null
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import java.io.File;
+
+public class AppFuseMount implements Parcelable {
+ final public File mountPoint;
+ final public ParcelFileDescriptor fd;
+
+ public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) {
+ this.mountPoint = mountPoint;
+ this.fd = fd;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.mountPoint.getPath());
+ dest.writeParcelable(fd, flags);
+ }
+
+ public static final Parcelable.Creator<AppFuseMount> CREATOR =
+ new Parcelable.Creator<AppFuseMount>() {
+ @Override
+ public AppFuseMount createFromParcel(Parcel in) {
+ return new AppFuseMount(new File(in.readString()), in.readParcelable(null));
+ }
+
+ @Override
+ public AppFuseMount[] newArray(int size) {
+ return new AppFuseMount[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 80c55fb..7591488 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -27,6 +27,8 @@
SystemProperties.getInt("ro.debuggable", 0) == 1;
public static final int FACTORYTEST =
SystemProperties.getInt("ro.factorytest", 0);
+ public static final boolean CONTROL_PRIVAPP_PERMISSIONS =
+ SystemProperties.getBoolean("ro.control_privapp_permissions", false);
// ------ ro.config.* -------- //
public static final boolean CONFIG_LOW_RAM =
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index e57a224..304c31d 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -16,7 +16,7 @@
package com.android.internal.os;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.os.Build;
@@ -113,7 +113,7 @@
}
// Bring up crash dialog, wait for it to be dismissed
- ActivityManagerNative.getDefault().handleApplicationCrash(
+ ActivityManager.getService().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
} catch (Throwable t2) {
if (t2 instanceof DeadObjectException) {
@@ -379,7 +379,7 @@
*/
public static void wtf(String tag, Throwable t, boolean system) {
try {
- if (ActivityManagerNative.getDefault().handleApplicationWtf(
+ if (ActivityManager.getService().handleApplicationWtf(
mApplicationObject, tag, system,
new ApplicationErrorReport.ParcelableCrashInfo(t))) {
// The Activity Manager has already written us off -- now exit.
diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java
index e76b395..f904150 100644
--- a/core/java/com/android/internal/os/TransferPipe.java
+++ b/core/java/com/android/internal/os/TransferPipe.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -32,13 +33,13 @@
/**
* Helper for transferring data through a pipe from a client app.
*/
-public final class TransferPipe implements Runnable {
+public final class TransferPipe implements Runnable, Closeable {
static final String TAG = "TransferPipe";
static final boolean DEBUG = false;
static final long DEFAULT_TIMEOUT = 5000; // 5 seconds
- final Thread mThread;;
+ final Thread mThread;
final ParcelFileDescriptor[] mFds;
FileDescriptor mOutFd;
@@ -54,8 +55,13 @@
}
public TransferPipe() throws IOException {
+ this(null);
+ }
+
+ public TransferPipe(String bufferPrefix) throws IOException {
mThread = new Thread(this, "TransferPipe");
mFds = ParcelFileDescriptor.createPipe();
+ mBufferPrefix = bufferPrefix;
}
ParcelFileDescriptor getReadFd() {
@@ -70,6 +76,11 @@
mBufferPrefix = prefix;
}
+ public static void dumpAsync(IBinder binder, FileDescriptor out, String[] args)
+ throws IOException, RemoteException {
+ goDump(binder, out, args);
+ }
+
static void go(Caller caller, IInterface iface, FileDescriptor out,
String prefix, String[] args) throws IOException, RemoteException {
go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
@@ -86,12 +97,9 @@
return;
}
- TransferPipe tp = new TransferPipe();
- try {
+ try (TransferPipe tp = new TransferPipe()) {
caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
tp.go(out, timeout);
- } finally {
- tp.kill();
}
}
@@ -111,12 +119,9 @@
return;
}
- TransferPipe tp = new TransferPipe();
- try {
+ try (TransferPipe tp = new TransferPipe()) {
binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
tp.go(out, timeout);
- } finally {
- tp.kill();
}
}
@@ -173,6 +178,11 @@
}
}
+ @Override
+ public void close() {
+ kill();
+ }
+
public void kill() {
synchronized (this) {
closeFd(0);
diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
index bed7c1ba..eb75bd4 100644
--- a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
+++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
+import android.os.UserHandle;
import android.provider.Settings;
/**
@@ -72,7 +73,7 @@
Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
intent.setData(getPhoneUri(context));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
+ context.startActivityAsUser(intent, UserHandle.CURRENT);
}
/**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 50621f4..2a004cfb 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -21,7 +21,7 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.*;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.SearchManager;
import android.os.UserHandle;
@@ -3715,9 +3715,9 @@
}
public static void sendCloseSystemWindows(Context context, String reason) {
- if (ActivityManagerNative.isSystemReady()) {
+ if (ActivityManager.isSystemReady()) {
try {
- ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ ActivityManager.getService().closeSystemDialogs(reason);
} catch (RemoteException e) {
}
}
diff --git a/core/java/com/android/internal/policy/PipMotionHelper.java b/core/java/com/android/internal/policy/PipMotionHelper.java
index 0543442..944cd32 100644
--- a/core/java/com/android/internal/policy/PipMotionHelper.java
+++ b/core/java/com/android/internal/policy/PipMotionHelper.java
@@ -18,7 +18,7 @@
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.graphics.Rect;
import android.os.Handler;
@@ -51,7 +51,7 @@
public void resizeToBounds(Rect toBounds) {
mHandler.post(() -> {
if (mActivityManager == null) {
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
}
try {
mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index cbacf26..62d506f 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -41,8 +41,12 @@
// Allows snapping to anywhere along the edge of the screen
private static final int SNAP_MODE_EDGE = 2;
+ // The friction multiplier to control how slippery the PIP is when flung
private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
+ // The fraction of the stack width to show when minimized
+ private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f;
+
private final Context mContext;
private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
@@ -122,6 +126,18 @@
}
/**
+ * Applies the offset to the {@param stackBounds} to adjust it to a minimized state.
+ */
+ public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize) {
+ int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * stackBounds.width());
+ if (stackBounds.left <= movementBounds.centerX()) {
+ stackBounds.offsetTo(-stackBounds.width() + visibleWidth, stackBounds.top);
+ } else {
+ stackBounds.offsetTo(displaySize.x - visibleWidth, stackBounds.top);
+ }
+ }
+
+ /**
* @return returns a fraction that describes where along the {@param movementBounds} the
* {@param stackBounds} are. If the {@param stackBounds} are not currently on the
* {@param movementBounds} exactly, then they will be snapped to the movement bounds.
@@ -208,15 +224,19 @@
final int fromTop = Math.abs(stackBounds.top - movementBounds.top);
final int fromRight = Math.abs(movementBounds.right - stackBounds.left);
final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top);
+ final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right,
+ stackBounds.left));
+ final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
+ stackBounds.top));
boundsOut.set(stackBounds);
if (fromLeft <= fromTop && fromLeft <= fromRight && fromLeft <= fromBottom) {
- boundsOut.offsetTo(movementBounds.left, stackBounds.top);
+ boundsOut.offsetTo(movementBounds.left, boundedTop);
} else if (fromTop <= fromLeft && fromTop <= fromRight && fromTop <= fromBottom) {
- boundsOut.offsetTo(stackBounds.left, movementBounds.top);
+ boundsOut.offsetTo(boundedLeft, movementBounds.top);
} else if (fromRight < fromLeft && fromRight < fromTop && fromRight < fromBottom) {
- boundsOut.offsetTo(movementBounds.right, stackBounds.top);
+ boundsOut.offsetTo(movementBounds.right, boundedTop);
} else {
- boundsOut.offsetTo(stackBounds.left, movementBounds.bottom);
+ boundsOut.offsetTo(boundedLeft, movementBounds.bottom);
}
}
diff --git a/core/java/com/android/internal/util/ToBooleanFunction.java b/core/java/com/android/internal/util/ToBooleanFunction.java
new file mode 100644
index 0000000..83866c2
--- /dev/null
+++ b/core/java/com/android/internal/util/ToBooleanFunction.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.util;
+
+import java.util.function.Function;
+
+/**
+ * Represents a function that produces an boolean-valued result. This is the
+ * {@code boolean}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToBooleanFunction<T> {
+
+ /**
+ * Applies this function to the given argument.
+ *
+ * @param value the function argument
+ * @return the function result
+ */
+ boolean apply(T value);
+}
diff --git a/core/java/com/android/internal/view/OneShotPreDrawListener.java b/core/java/com/android/internal/view/OneShotPreDrawListener.java
new file mode 100644
index 0000000..98ffd82
--- /dev/null
+++ b/core/java/com/android/internal/view/OneShotPreDrawListener.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.view;
+
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+/**
+ * An OnPreDrawListener that will remove itself after one OnPreDraw call. Typical
+ * usage is:
+ * <pre><code>
+ * OneShotPreDrawListener.add(view, () -> { view.doSomething(); })
+ * </code></pre>
+ * <p>
+ * The onPreDraw always returns true.
+ * <p>
+ * The listener will also remove itself from the ViewTreeObserver when the view
+ * is detached from the view hierarchy. In that case, the Runnable will never be
+ * executed.
+ */
+public class OneShotPreDrawListener implements ViewTreeObserver.OnPreDrawListener,
+ View.OnAttachStateChangeListener {
+ private final View mView;
+ private ViewTreeObserver mViewTreeObserver;
+ private final Runnable mRunnable;
+
+ private OneShotPreDrawListener(View view, Runnable runnable) {
+ mView = view;
+ mViewTreeObserver = view.getViewTreeObserver();
+ mRunnable = runnable;
+ }
+
+ /**
+ * Creates a OneShotPreDrawListener and adds it to view's ViewTreeObserver.
+ * @param view The view whose ViewTreeObserver the OnPreDrawListener should listen.
+ * @param runnable The Runnable to execute in the OnPreDraw (once)
+ * @return The added OneShotPreDrawListener. It can be removed prior to
+ * the onPreDraw by calling {@link #removeListener()}.
+ */
+ public static OneShotPreDrawListener add(View view, Runnable runnable) {
+ OneShotPreDrawListener listener = new OneShotPreDrawListener(view, runnable);
+ view.getViewTreeObserver().addOnPreDrawListener(listener);
+ view.addOnAttachStateChangeListener(listener);
+ return listener;
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ removeListener();
+ mRunnable.run();
+ return true;
+ }
+
+ /**
+ * Removes the listener from the ViewTreeObserver. This is useful to call if the
+ * callback should be removed prior to {@link #onPreDraw()}.
+ */
+ public void removeListener() {
+ if (mViewTreeObserver.isAlive()) {
+ mViewTreeObserver.removeOnPreDrawListener(this);
+ } else {
+ mView.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ mView.removeOnAttachStateChangeListener(this);
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mViewTreeObserver = v.getViewTreeObserver();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ removeListener();
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 71252fb..b0bc81b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -36,7 +36,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
@@ -682,10 +682,10 @@
return;
}
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
Log.d(TAG, "Setting owner info");
- mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
+ storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error changing user info", e);
}
@@ -746,9 +746,9 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... dummy) {
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
- mountService.changeEncryptionPassword(type, password);
+ storageManager.changeEncryptionPassword(type, password);
} catch (RemoteException e) {
Log.e(TAG, "Error changing encryption password", e);
}
@@ -1122,9 +1122,9 @@
return;
}
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
- mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
+ storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
} catch (RemoteException e) {
Log.e(TAG, "Error changing pattern visible state", e);
}
@@ -1145,9 +1145,9 @@
return;
}
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
- mountService.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
+ storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
} catch (RemoteException e) {
Log.e(TAG, "Error changing password visible state", e);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 429131b..168da5f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -25,6 +25,7 @@
import android.os.Environment;
import android.os.Process;
import android.os.storage.StorageManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -129,6 +130,9 @@
final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
new ArrayMap<>();
+
+ final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -194,6 +198,10 @@
return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
}
+ public ArraySet<String> getPrivAppPermissions(String packageName) {
+ return mPrivAppPermissions.get(packageName);
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -507,6 +515,8 @@
associatedPkgs.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("privapp-permissions".equals(name) && allowAppConfigs) {
+ readPrivAppPermissions(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
@@ -584,4 +594,32 @@
XmlUtils.skipCurrentTag(parser);
}
}
+
+ void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+ String packageName = parser.getAttributeValue(null, "package");
+ if (TextUtils.isEmpty(packageName)) {
+ Slog.w(TAG, "package is required for <privapp-permissions> in "
+ + parser.getPositionDescription());
+ return;
+ }
+
+ ArraySet<String> permissions = mPrivAppPermissions.get(packageName);
+ if (permissions == null) {
+ permissions = new ArraySet<>();
+ }
+ int depth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, depth)) {
+ String name = parser.getName();
+ if ("permission".equals(name)) {
+ String permName = parser.getAttributeValue(null, "name");
+ if (TextUtils.isEmpty(permName)) {
+ Slog.w(TAG, "name is required for <permission> in "
+ + parser.getPositionDescription());
+ continue;
+ }
+ permissions.add(permName);
+ }
+ }
+ mPrivAppPermissions.put(packageName, permissions);
+ }
}
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 0de46e6..7e417b4 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -93,7 +93,7 @@
if (jbitmap) {
// Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
}
sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 7fc79d2..c920b8d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -70,7 +70,7 @@
static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- return Typeface::setDefault(face);
+ Typeface::setDefault(face);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 1a33d91..10090a1 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -34,6 +34,8 @@
#include "core_jni_helpers.h"
using android::AndroidRuntime;
+using android::hardware::hidl_vec;
+using android::hardware::hidl_string;
#define PACKAGE_PATH "android/os"
#define CLASS_NAME "HwBinder"
@@ -41,10 +43,15 @@
namespace android {
+static jclass gArrayListClass;
+static struct {
+ jmethodID size;
+ jmethodID get;
+} gArrayListMethods;
+
static struct fields_t {
jfieldID contextID;
jmethodID onTransactID;
-
} gFields;
// static
@@ -199,45 +206,46 @@
static void JHwBinder_native_registerService(
JNIEnv *env,
jobject thiz,
- jstring serviceNameObj,
- jint versionMajor,
- jint versionMinor) {
+ jobject interfaceChainArrayList,
+ jstring serviceNameObj) {
if (serviceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return;
}
- if (versionMajor < 0
- || versionMajor > 65535
- || versionMinor < 0
- || versionMinor > 65535) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
-
+ const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
if (serviceName == NULL) {
return; // XXX exception already pending?
}
- using android::hidl::manager::V1_0::IServiceManager;
+ jint numInterfaces = env->CallIntMethod(interfaceChainArrayList,
+ gArrayListMethods.size);
+ hidl_string *strings = new hidl_string[numInterfaces];
- const IServiceManager::Version kVersion {
- .major = static_cast<uint16_t>(versionMajor),
- .minor = static_cast<uint16_t>(versionMinor),
- };
+ for (jint i = 0; i < numInterfaces; i++) {
+ jstring strObj = static_cast<jstring>(
+ env->CallObjectMethod(interfaceChainArrayList,
+ gArrayListMethods.get,
+ i)
+ );
+ const char * str = env->GetStringUTFChars(strObj, nullptr);
+ strings[i] = hidl_string(str);
+ env->ReleaseStringUTFChars(strObj, str);
+ }
+
+ hidl_vec<hidl_string> interfaceChain;
+ interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */);
+
+ using android::hidl::manager::V1_0::IServiceManager;
sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
bool ok = hardware::defaultServiceManager()->add(
- String8(String16(
- reinterpret_cast<const char16_t *>(serviceName),
- env->GetStringLength(serviceNameObj))).string(),
- binder,
- kVersion);
+ interfaceChain,
+ serviceName,
+ binder);
- env->ReleaseStringCritical(serviceNameObj, serviceName);
+ env->ReleaseStringUTFChars(serviceNameObj, serviceName);
serviceName = NULL;
if (ok) {
@@ -251,52 +259,43 @@
static jobject JHwBinder_native_getService(
JNIEnv *env,
jclass /* clazzObj */,
- jstring serviceNameObj,
- jint versionMajor,
- jint versionMinor) {
+ jstring ifaceNameObj,
+ jstring serviceNameObj) {
+
+ if (ifaceNameObj == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
if (serviceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
- if (versionMajor < 0
- || versionMajor > 65535
- || versionMinor < 0
- || versionMinor > 65535) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
+ const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
+ if (ifaceName == NULL) {
+ return NULL; // XXX exception already pending?
}
-
- const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
-
+ const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
if (serviceName == NULL) {
- return NULL; // XXX exception already pending?
+ env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+ return NULL; // XXX exception already pending?
}
- using android::hidl::manager::V1_0::IServiceManager;
-
- const IServiceManager::Version kVersion {
- .major = static_cast<uint16_t>(versionMajor),
- .minor = static_cast<uint16_t>(versionMinor),
- };
-
LOG(INFO) << "looking for service '"
- << String8(String16(
- reinterpret_cast<const char16_t *>(serviceName),
- env->GetStringLength(serviceNameObj))).string()
+ << serviceName
<< "'";
sp<hardware::IBinder> service;
hardware::defaultServiceManager()->get(
- String8(String16(
- reinterpret_cast<const char16_t *>(serviceName),
- env->GetStringLength(serviceNameObj))).string(),
- kVersion,
+ ifaceName,
+ serviceName,
[&service](sp<hardware::IBinder> out) {
service = out;
});
- env->ReleaseStringCritical(serviceNameObj, serviceName);
+ env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+ ifaceName = NULL;
+ env->ReleaseStringUTFChars(serviceNameObj, serviceName);
serviceName = NULL;
if (service == NULL) {
@@ -318,16 +317,21 @@
"(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
(void *)JHwBinder_native_transact },
- { "registerService", "(Ljava/lang/String;II)V",
+ { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V",
(void *)JHwBinder_native_registerService },
- { "getService", "(Ljava/lang/String;II)L" PACKAGE_PATH "/IHwBinder;",
+ { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
};
namespace android {
int register_android_os_HwBinder(JNIEnv *env) {
+ jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+ gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
+ gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I");
+ gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;");
+
return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
index 6bd82e9..0920488 100644
--- a/core/jni/android_os_HwBlob.h
+++ b/core/jni/android_os_HwBlob.h
@@ -20,6 +20,7 @@
#include <android-base/macros.h>
#include <jni.h>
#include <hidl/HidlSupport.h>
+#include <hwbinder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 7387b29..a10d807 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -26,6 +26,7 @@
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -267,17 +268,17 @@
const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
if (interfaceName) {
- hardware::Parcel *parcel =
- JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
- status_t err = parcel->writeInterfaceToken(
- String16(
- reinterpret_cast<const char16_t *>(interfaceName),
- env->GetStringLength(interfaceNameObj)));
+ String8 nameCopy = String8(String16(
+ reinterpret_cast<const char16_t *>(interfaceName),
+ env->GetStringLength(interfaceNameObj)));
env->ReleaseStringCritical(interfaceNameObj, interfaceName);
interfaceName = NULL;
+ hardware::Parcel *parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ status_t err = parcel->writeInterfaceToken(nameCopy.string());
signalExceptionForError(env, err);
}
}
@@ -294,17 +295,18 @@
const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
if (interfaceName) {
- hardware::Parcel *parcel =
- JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
- bool valid = parcel->enforceInterface(
- String16(
- reinterpret_cast<const char16_t *>(interfaceName),
- env->GetStringLength(interfaceNameObj)));
+ String8 interfaceNameCopy = String8(String16(
+ reinterpret_cast<const char16_t *>(interfaceName),
+ env->GetStringLength(interfaceNameObj)));
env->ReleaseStringCritical(interfaceNameObj, interfaceName);
interfaceName = NULL;
+ hardware::Parcel *parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ bool valid = parcel->enforceInterface(interfaceNameCopy.string());
+
if (!valid) {
jniThrowException(
env,
@@ -382,7 +384,7 @@
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
- status_t err = status.writeToParcel(parcel);
+ status_t err = ::android::hardware::writeToParcel(status, parcel);
signalExceptionForError(env, err);
}
@@ -393,7 +395,7 @@
JHwParcel::GetNativeContext(env, thiz)->getParcel();
Status status;
- status_t err = status.readFromParcel(*parcel);
+ status_t err = ::android::hardware::readFromParcel(&status, *parcel);
signalExceptionForError(env, err);
}
@@ -424,8 +426,8 @@
status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle);
if (err == OK) {
- err = s->writeEmbeddedToParcel(
- parcel, parentHandle, 0 /* parentOffset */);
+ err = ::android::hardware::writeEmbeddedToParcel(
+ *s, parcel, parentHandle, 0 /* parentOffset */);
}
signalExceptionForError(env, err);
@@ -452,7 +454,8 @@
if (err == OK) { \
size_t childHandle; \
\
- err = vec->writeEmbeddedToParcel( \
+ err = ::android::hardware::writeEmbeddedToParcel( \
+ *vec, \
parcel, \
parentHandle, \
0 /* parentOffset */, \
@@ -507,7 +510,8 @@
if (err == OK) {
size_t childHandle;
- err = vec->writeEmbeddedToParcel(
+ err = ::android::hardware::writeEmbeddedToParcel(
+ *vec,
parcel,
parentHandle,
0 /* parentOffset */,
@@ -567,7 +571,8 @@
return NULL;
}
- status_t err = const_cast<hidl_string *>(s)->readEmbeddedFromParcel(
+ status_t err = ::android::hardware::readEmbeddedFromParcel(
+ const_cast<hidl_string *>(s),
*parcel, parentHandle, 0 /* parentOffset */);
if (err != OK) {
@@ -596,8 +601,8 @@
\
size_t childHandle; \
\
- status_t err = const_cast<hidl_vec<Type> *>(vec) \
- ->readEmbeddedFromParcel( \
+ status_t err = ::android::hardware::readEmbeddedFromParcel( \
+ const_cast<hidl_vec<Type> *>(vec), \
*parcel, \
parentHandle, \
0 /* parentOffset */, \
@@ -638,8 +643,8 @@
size_t childHandle;
- status_t err = const_cast<hidl_vec<bool> *>(vec)
- ->readEmbeddedFromParcel(
+ status_t err = ::android::hardware::readEmbeddedFromParcel(
+ const_cast<hidl_vec<bool> *>(vec),
*parcel,
parentHandle,
0 /* parentOffset */,
@@ -700,12 +705,13 @@
}
size_t childHandle;
- status_t err = const_cast<string_vec *>(vec)->readEmbeddedFromParcel(
+ status_t err = ::android::hardware::readEmbeddedFromParcel(
+ const_cast<string_vec *>(vec),
*parcel, parentHandle, 0 /* parentOffset */, &childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
- err = const_cast<hidl_vec<hidl_string> *>(vec)
- ->readEmbeddedFromParcel(
+ err = android::hardware::readEmbeddedFromParcel(
+ const_cast<hidl_vec<hidl_string> *>(vec),
*parcel,
childHandle,
i * sizeof(hidl_string),
@@ -759,14 +765,16 @@
if (err == OK) {
size_t childHandle;
- err = vec->writeEmbeddedToParcel(
+ err = ::android::hardware::writeEmbeddedToParcel(
+ *vec,
parcel,
parentHandle,
0 /* parentOffset */,
&childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
- err = (*vec)[i].writeEmbeddedToParcel(
+ err = ::android::hardware::writeEmbeddedToParcel(
+ (*vec)[i],
parcel,
childHandle,
i * sizeof(hidl_string));
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 1743731..b9376d8 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -111,7 +111,7 @@
}
status_t error;
- sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
+ sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error));
if (buffer == NULL) {
if (kDebugGraphicBuffer) {
ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index bba3d76..da059e3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -319,12 +319,6 @@
bool force_mount_namespace) {
// See storage config details at http://source.android.com/tech/storage/
- // Create a second private mount namespace for our process
- if (unshare(CLONE_NEWNS) == -1) {
- ALOGW("Failed to unshare(): %s", strerror(errno));
- return false;
- }
-
String8 storageSource;
if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
storageSource = "/mnt/runtime/default";
@@ -332,10 +326,17 @@
storageSource = "/mnt/runtime/read";
} else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
storageSource = "/mnt/runtime/write";
- } else {
+ } else if (!force_mount_namespace) {
// Sane default of no storage visible
return true;
}
+
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ ALOGW("Failed to unshare(): %s", strerror(errno));
+ return false;
+ }
+
if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
@@ -628,6 +629,12 @@
}
} else if (pid > 0) {
// the parent process
+
+ // We blocked SIGCHLD prior to a fork, we unblock it here.
+ if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
+ ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+ }
}
return pid;
}
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
index 2babe44..e270911 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -241,6 +241,18 @@
is_sock(false) {
}
+ static bool StartsWith(const std::string& str, const std::string& prefix) {
+ return str.compare(0, prefix.size(), prefix) == 0;
+ }
+
+ static bool EndsWith(const std::string& str, const std::string& suffix) {
+ if (suffix.size() > str.size()) {
+ return false;
+ }
+
+ return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+ }
+
// Returns true iff. a given path is whitelisted. A path is whitelisted
// if it belongs to the whitelist (see kPathWhitelist) or if it's a path
// under /system/framework that ends with ".jar" or if it is a system
@@ -252,31 +264,42 @@
}
}
- static const char* kFrameworksPrefix = "/system/framework/";
- static const char* kJarSuffix = ".jar";
- if (android::base::StartsWith(path, kFrameworksPrefix)
- && android::base::EndsWith(path, kJarSuffix)) {
+ static const std::string kFrameworksPrefix = "/system/framework/";
+ static const std::string kJarSuffix = ".jar";
+ if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
return true;
}
// Whitelist files needed for Runtime Resource Overlay, like these:
+ // /system/vendor/overlay/framework-res.apk
+ // /system/vendor/overlay-subdir/pg/framework-res.apk
// /vendor/overlay/framework-res.apk
// /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
// /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
- // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
- static const char* kOverlayDir = "/vendor/overlay/";
- static const char* kApkSuffix = ".apk";
+ // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
+ // See AssetManager.cpp for more details on overlay-subdir.
+ static const std::string kOverlayDir = "/system/vendor/overlay/";
+ static const std::string kVendorOverlayDir = "/vendor/overlay";
+ static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
+ static const std::string kApkSuffix = ".apk";
- if (android::base::StartsWith(path, kOverlayDir)
- && android::base::EndsWith(path, kApkSuffix)
+ if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
+ || StartsWith(path, kVendorOverlayDir))
+ && EndsWith(path, kApkSuffix)
&& path.find("/../") == std::string::npos) {
return true;
}
- static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
- static const char* kOverlayIdmapSuffix = ".apk@idmap";
- if (android::base::StartsWith(path, kOverlayIdmapPrefix)
- && android::base::EndsWith(path, kOverlayIdmapSuffix)) {
+ static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
+ static const std::string kOverlayIdmapSuffix = ".apk@idmap";
+ if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+ && path.find("/../") == std::string::npos) {
+ return true;
+ }
+
+ // All regular files that are placed under this path are whitelisted automatically.
+ static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+ if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
return true;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4eebea6..fbad143 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -501,6 +501,10 @@
<protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
+ <!-- Added in O -->
+ <!-- TODO: temporary broadcast used by AutoFillManagerServiceImpl; will be removed -->
+ <protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -717,6 +721,7 @@
android:priority="400" />
<!-- Allows an app to access precise location.
+ Alternatively, you might want {@link #ACCESS_COARSE_LOCATION}.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_FINE_LOCATION"
@@ -726,6 +731,7 @@
android:protectionLevel="dangerous|ephemeral" />
<!-- Allows an app to access approximate location.
+ Alternatively, you might want {@link #ACCESS_FINE_LOCATION}.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_COARSE_LOCATION"
@@ -2323,6 +2329,13 @@
<permission android:name="android.permission.BIND_VOICE_INTERACTION"
android:protectionLevel="signature" />
+ <!-- Must be required by a {@link android.service.autofill.AutoFillService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_AUTO_FILL"
+ android:protectionLevel="signature" />
+
<!-- Must be required by hotword enrollment application,
to ensure that only the system can interact with it.
@hide <p>Not for use by third-party applications.</p> -->
@@ -2937,11 +2950,11 @@
android:protectionLevel="signature" />
<!-- Must be required by an {@link
- android.service.notification.NotificationRankerService to ensure that only the system can bind to it.
+ android.service.notification.NotificationAssistantService to ensure that only the system
+ can bind to it.
<p>Protection level: signature
- @hide This is not a third-party API (intended for system apps). -->
-->
- <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
+ <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
android:protectionLevel="signature" />
<!-- Must be required by a {@link
@@ -3118,6 +3131,17 @@
<permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to manage auto-fill sessions.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_AUTO_FILL"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an app to set the theme overlay in /vendor/overlay
+ being used.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/drawable/watch_switch_track_material.xml b/core/res/res/color/watch_switch_track_color_material.xml
similarity index 73%
rename from core/res/res/drawable/watch_switch_track_material.xml
rename to core/res/res/color/watch_switch_track_color_material.xml
index 79e92a3..c7dc5d3 100644
--- a/core/res/res/drawable/watch_switch_track_material.xml
+++ b/core/res/res/color/watch_switch_track_color_material.xml
@@ -1,9 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
+
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
+
http://www.apache.org/licenses/LICENSE-2.0
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -12,10 +15,8 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false">
- <bitmap android:alpha="0.1" android:src="@drawable/watch_switch_track_mtrl_alpha" />
- </item>
- <item>
- <bitmap android:alpha="0.2" android:src="@drawable/watch_switch_track_mtrl_alpha" />
- </item>
-</selector>
+ <item android:state_enabled="false"
+ android:alpha="?attr/disabledAlpha"
+ android:color="?android:colorPrimary" />
+ <item android:color="?android:colorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-hdpi/watch_switch_track_mtrl.png
similarity index 100%
rename from core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-hdpi/watch_switch_track_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xhdpi/watch_switch_track_mtrl.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-xhdpi/watch_switch_track_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png
rename to core/res/res/drawable-xxhdpi/watch_switch_track_mtrl.png
Binary files differ
diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml
index 5881cf0..a1a845a 100644
--- a/core/res/res/layout-watch/preference_widget_switch.xml
+++ b/core/res/res/layout-watch/preference_widget_switch.xml
@@ -24,7 +24,8 @@
android:thumb="@drawable/watch_switch_thumb_material_anim"
android:thumbTint="@color/watch_switch_thumb_color_material"
android:thumbTintMode="multiply"
- android:track="@drawable/watch_switch_track_material"
+ android:track="@drawable/watch_switch_track_mtrl"
+ android:trackTint="@color/watch_switch_track_color_material"
android:focusable="false"
android:clickable="false"
android:background="@null" />
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index c63ec41..522efc5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -596,7 +596,7 @@
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"Fax de casa"</string>
<string name="phoneTypePager" msgid="7582359955394921732">"Cercapersones"</string>
<string name="phoneTypeOther" msgid="1544425847868765990">"Altres"</string>
- <string name="phoneTypeCallback" msgid="2712175203065678206">"Torna la trucada"</string>
+ <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolució de trucada"</string>
<string name="phoneTypeCar" msgid="8738360689616716982">"Cotxe"</string>
<string name="phoneTypeCompanyMain" msgid="540434356461478916">"Telèfon d\'empresa"</string>
<string name="phoneTypeIsdn" msgid="8022453193171370337">"XDSI"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 77b43b1..fa03897 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -258,7 +258,7 @@
<string name="permgrouplab_camera" msgid="4820372495894586615">"Cámara"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"hacer fotos y grabar vídeos"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Teléfono"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"hacer y administrar llamadas de teléfono"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"hacer y administrar llamadas telefónicas"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporales"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder a datos de sensores de tus constantes vitales"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar el contenido de la ventana"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 13218b7..9c26340 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1333,7 +1333,7 @@
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
- <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele gegevenslimiet bereikt"</string>
+ <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Mobiele datalimiet bereikt"</string>
<string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Wifi-gegevenslimiet bereikt"</string>
<string name="data_usage_limit_body" msgid="291731708279614081">"Gegev. onderbr. voor rest cyclus"</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Gegevenslimiet 2G-3G overschreden"</string>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 18bfd4d..72f589b 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -14,15 +14,15 @@
limitations under the License.
-->
<resources>
- <color name="background_material_dark">#ff232e33</color>
- <color name="background_floating_material_dark">#ff3e5059</color>
+ <color name="background_material_dark">#232E33</color>
+ <color name="background_floating_material_dark">#3E5059</color>
- <color name="accent_material_700">#ff2e4978</color>
- <color name="accent_material_light">#ff4285f4</color>
- <color name="accent_material_dark">#ff5e97f6</color>
- <color name="accent_material_50">#ffd0def7</color>
+ <color name="accent_material_700">#5385DB</color>
+ <color name="accent_material_light">#75A4F5</color>
+ <color name="accent_material_dark">#5E97F6</color>
+ <color name="accent_material_50">#93B7F5</color>
- <color name="primary_material_dark">#4D4D4D</color>
+ <color name="primary_material_dark">#33ffffff</color>
<color name="button_material_dark">#ff919699</color>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c3967e4..2d61e6e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8335,4 +8335,15 @@
<declare-styleable name="ShortcutCategories">
<attr name="name" />
</declare-styleable>
+
+ <!-- Attributes that are read when parsing a <font> tag, which is a child of
+ <font-family>. -->
+ <declare-styleable name="FontFamilyFont">
+ <attr name="fontStyle">
+ <enum name="normal" value="0" />
+ <enum name="italic" value="1" />
+ </attr>
+ <attr name="font" format="reference" />
+ <attr name="fontWeight" format="integer" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 89691e9..8f0350a 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -28,10 +28,10 @@
<color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
<color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
- <color name="accent_device_default_700">@color/material_deep_teal_700</color>
+ <color name="accent_device_default_700">@color/accent_material_700</color>
<color name="accent_device_default_light">@color/accent_material_light</color>
<color name="accent_device_default_dark">@color/accent_material_dark</color>
- <color name="accent_device_default_50">@color/material_deep_teal_50</color>
+ <color name="accent_device_default_50">@color/accent_material_50</color>
<color name="background_device_default_dark">@color/background_material_dark</color>
<color name="background_device_default_light">@color/background_material_light</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 92426c6..37feff8 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -36,8 +36,10 @@
<color name="tertiary_material_settings">@color/material_blue_grey_700</color>
<color name="quaternary_material_settings">@color/material_blue_grey_200</color>
+ <color name="accent_material_700">@color/material_deep_teal_700</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="accent_material_dark">@color/material_deep_teal_200</color>
+ <color name="accent_material_50">@color/material_deep_teal_50</color>
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d207c2b..996fd55 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1919,6 +1919,12 @@
mirror the content of the default display. -->
<bool name="config_localDisplaysMirrorContent">true</bool>
+ <!-- The default mode for the default display. One of the following values (See Display.java):
+ 0 - COLOR_MODE_DEFAULT
+ 7 - COLOR_MODE_SRGB
+ -->
+ <integer name="config_defaultDisplayDefaultColorMode">0</integer>
+
<!-- When true use the linux /dev/input/event subsystem to detect the switch changes
on the headphone/microphone jack. When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
@@ -2486,16 +2492,24 @@
<!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">10x10</string>
+ <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">8x8</string>
<!-- Max default size [WIDTHxHEIGHT] on screen for picture-in-picture windows to fit inside.
These values are in DPs and will be converted to pixel sizes internally. -->
- <string translatable="false" name="config_defaultPictureInPictureSize">216x135</string>
+ <string translatable="false" name="config_defaultPictureInPictureSize">192x120</string>
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x55</integer>
+ <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
+ ratio smaller than this is considered too tall and thin to be usable. -->
+ <item name="config_pictureInPictureMinAspectRatio" format="float" type="dimen">0.5</item>
+
+ <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
+ ratio larger than this is considered to wide and short to be usable. -->
+ <item name="config_pictureInPictureMaxAspectRatio" format="float" type="dimen">2.35</item>
+
<!-- Controls the snap mode for the docked stack divider
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c06a93d..ed68582 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2756,6 +2756,9 @@
<eat-comment />
<public-group type="attr" first-id="0x01010531">
+ <public name="fontStyle" />
+ <public name="font" />
+ <public name="fontWeight" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 07c4c69..6c0dc35 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -309,10 +309,13 @@
<java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_guestUserEphemeral" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+ <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
<java-symbol type="bool" name="config_enableAppWidgetService" />
<java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
<java-symbol type="string" name="config_defaultPictureInPictureSize" />
<java-symbol type="integer" name="config_defaultPictureInPictureGravity" />
+ <java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" />
+ <java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
diff --git a/core/tests/coretests/res/layout/remote_view_host.xml b/core/tests/coretests/res/layout/remote_view_host.xml
index 19d0a73..6809508 100644
--- a/core/tests/coretests/res/layout/remote_view_host.xml
+++ b/core/tests/coretests/res/layout/remote_view_host.xml
@@ -19,7 +19,7 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-</LinearLayout>
+ android:layout_height="match_parent" />
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml b/core/tests/coretests/res/layout/remote_views_text.xml
similarity index 68%
rename from tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml
rename to core/tests/coretests/res/layout/remote_views_text.xml
index 5322411..a265d2e 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/empty.xml
+++ b/core/tests/coretests/res/layout/remote_views_text.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2016 The Android Open Source Project
~
@@ -11,6 +12,10 @@
~ 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.
+ ~ limitations under the License
-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/core/tests/coretests/res/layout/remote_views_viewstub.xml b/core/tests/coretests/res/layout/remote_views_viewstub.xml
new file mode 100644
index 0000000..d532749
--- /dev/null
+++ b/core/tests/coretests/res/layout/remote_views_viewstub.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <ViewStub android:id="@+id/viewStub"
+ android:inflatedId="@+id/stub_inflated"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index f28ba7e..e9e8bfc 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -17,7 +17,7 @@
package android.app.activity;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -304,10 +304,10 @@
public void testSetSticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
- ActivityManagerNative.getDefault().unbroadcastIntent(null, intent,
+ ActivityManager.getService().unbroadcastIntent(null, intent,
UserHandle.myUserId());
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
addIntermediate("finished-broadcast");
IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
@@ -319,9 +319,9 @@
public void testClearSticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
- ActivityManagerNative.getDefault().unbroadcastIntent(
+ ActivityManager.getService().unbroadcastIntent(
null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null),
UserHandle.myUserId());
addIntermediate("finished-unbroadcast");
@@ -334,10 +334,10 @@
public void testReplaceSticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
intent.putExtra("test", LaunchpadActivity.DATA_2);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
addIntermediate("finished-broadcast");
IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
@@ -351,7 +351,7 @@
public void testReceiveSticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1);
}
@@ -361,10 +361,10 @@
public void testReceive2Sticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null);
intent.putExtra("test", LaunchpadActivity.DATA_2);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.myUserId());
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2);
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
index 06c495e..5af2667 100644
--- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -21,7 +21,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -31,14 +31,14 @@
private static final boolean localLOGV = true;
public static final String TAG = "PackageHelperTests";
protected final String PREFIX = "android.content.pm";
- private IMountService mMs;
+ private IStorageManager mSm;
private String fullId;
private String fullId2;
- private IMountService getMs() {
+ private IStorageManager getSm() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
- return IMountService.Stub.asInterface(service);
+ return IStorageManager.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
@@ -47,12 +47,12 @@
private void cleanupContainers() throws RemoteException {
Log.d(TAG,"cleanUp");
- IMountService ms = getMs();
- String[] containers = ms.getSecureContainerList();
+ IStorageManager sm = getSm();
+ String[] containers = sm.getSecureContainerList();
for (int i = 0; i < containers.length; i++) {
if (containers[i].startsWith(PREFIX)) {
Log.d(TAG,"cleaing up "+containers[i]);
- ms.destroySecureContainer(containers[i], true);
+ sm.destroySecureContainer(containers[i], true);
}
}
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index b5f0617..a15cba0 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -46,7 +46,7 @@
import android.os.StatFs;
import android.os.SystemClock;
import android.os.UserManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
@@ -1149,12 +1149,12 @@
}
}
- IMountService getMs() {
+ IStorageManager getSm() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
- return IMountService.Stub.asInterface(service);
+ return IStorageManager.Stub.asInterface(service);
} else {
- Log.e(TAG, "Can't get mount service");
+ Log.e(TAG, "Can't get storagemanager service");
}
return null;
}
@@ -1185,7 +1185,7 @@
try {
// Wait on observer
synchronized (observer) {
- int ret = getMs().mountVolume(path);
+ int ret = getSm().mountVolume(path);
if (ret != StorageResultCode.OperationSucceeded) {
throw new Exception("Could not mount the media");
}
@@ -1224,7 +1224,7 @@
try {
// Wait on observer
synchronized (observer) {
- getMs().unmountVolume(path, true, false);
+ getSm().unmountVolume(path, true, false);
long waitTime = 0;
while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
observer.wait(WAIT_TIME_INCR);
@@ -2754,7 +2754,7 @@
}
}
- /* This test creates a stale container via MountService and then installs
+ /* This test creates a stale container via StorageManagerService and then installs
* a package and verifies that the stale container is cleaned up and install
* is successful.
* Please note that this test is very closely tied to the framework's
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index fcc6389..4f2387d 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -18,14 +18,14 @@
import android.net.IpPrefix;
import android.os.Parcel;
-import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.junit.Assert.assertArrayEquals;
import java.net.InetAddress;
import java.util.Random;
import junit.framework.TestCase;
+import static android.test.MoreAsserts.assertNotEqual;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
public class IpPrefixTest extends TestCase {
@@ -242,25 +242,42 @@
@SmallTest
public void testHashCode() {
- IpPrefix p;
- int oldCode = -1;
+ IpPrefix p = new IpPrefix(new byte[4], 0);
Random random = new Random();
for (int i = 0; i < 100; i++) {
+ final IpPrefix oldP = p;
if (random.nextBoolean()) {
// IPv4.
byte[] b = new byte[4];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(33));
- assertNotEqual(oldCode, p.hashCode());
- oldCode = p.hashCode();
} else {
// IPv6.
byte[] b = new byte[16];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(129));
- assertNotEqual(oldCode, p.hashCode());
- oldCode = p.hashCode();
}
+ if (p.equals(oldP)) {
+ assertEquals(p.hashCode(), oldP.hashCode());
+ }
+ if (p.hashCode() != oldP.hashCode()) {
+ assertNotEqual(p, oldP);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testHashCodeIsNotConstant() {
+ IpPrefix[] prefixes = {
+ new IpPrefix("2001:db8:f00::ace:d00d/127"),
+ new IpPrefix("192.0.2.0/23"),
+ new IpPrefix("::/0"),
+ new IpPrefix("0.0.0.0/0"),
+ };
+ for (int i = 0; i < prefixes.length; i++) {
+ for (int j = i + 1; j < prefixes.length; j++) {
+ assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+ }
}
}
diff --git a/core/tests/coretests/src/android/os/storage/AsecTests.java b/core/tests/coretests/src/android/os/storage/AsecTests.java
index 4f724fe..e9a810d 100644
--- a/core/tests/coretests/src/android/os/storage/AsecTests.java
+++ b/core/tests/coretests/src/android/os/storage/AsecTests.java
@@ -50,21 +50,21 @@
}
private void cleanupContainers() throws RemoteException {
- IMountService ms = getMs();
- String[] containers = ms.getSecureContainerList();
+ IStorageManager sm = getSm();
+ String[] containers = sm.getSecureContainerList();
for (int i = 0; i < containers.length; i++) {
if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) {
if (localLOGV)
Log.i(TAG, "Cleaning: " + containers[i]);
- ms.destroySecureContainer(containers[i], true);
+ sm.destroySecureContainer(containers[i], true);
}
}
}
private boolean containerExists(String localId) throws RemoteException {
- IMountService ms = getMs();
- String[] containers = ms.getSecureContainerList();
+ IStorageManager sm = getSm();
+ String[] containers = sm.getSecureContainerList();
String fullId = SECURE_CONTAINER_PREFIX + localId;
for (int i = 0; i < containers.length; i++) {
@@ -80,8 +80,8 @@
assertTrue("Media should be mounted", isMediaMounted());
String fullId = SECURE_CONTAINER_PREFIX + localId;
- IMountService ms = getMs();
- return ms.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(),
+ IStorageManager sm = getSm();
+ return sm.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(),
isExternal);
}
@@ -89,8 +89,8 @@
assertTrue("Media should be mounted", isMediaMounted());
String fullId = SECURE_CONTAINER_PREFIX + localId;
- IMountService ms = getMs();
- return ms.mountSecureContainer(fullId, key, android.os.Process.myUid(), true);
+ IStorageManager sm = getSm();
+ return sm.mountSecureContainer(fullId, key, android.os.Process.myUid(), true);
}
private int renameContainer(String localId1, String localId2) throws Exception {
@@ -98,47 +98,47 @@
String fullId1 = SECURE_CONTAINER_PREFIX + localId1;
String fullId2 = SECURE_CONTAINER_PREFIX + localId2;
- IMountService ms = getMs();
- return ms.renameSecureContainer(fullId1, fullId2);
+ IStorageManager sm = getSm();
+ return sm.renameSecureContainer(fullId1, fullId2);
}
private int unmountContainer(String localId, boolean force) throws Exception {
assertTrue("Media should be mounted", isMediaMounted());
String fullId = SECURE_CONTAINER_PREFIX + localId;
- IMountService ms = getMs();
- return ms.unmountSecureContainer(fullId, force);
+ IStorageManager sm = getSm();
+ return sm.unmountSecureContainer(fullId, force);
}
private int destroyContainer(String localId, boolean force) throws Exception {
assertTrue("Media should be mounted", isMediaMounted());
String fullId = SECURE_CONTAINER_PREFIX + localId;
- IMountService ms = getMs();
- return ms.destroySecureContainer(fullId, force);
+ IStorageManager sm = getSm();
+ return sm.destroySecureContainer(fullId, force);
}
private boolean isContainerMounted(String localId) throws Exception {
assertTrue("Media should be mounted", isMediaMounted());
String fullId = SECURE_CONTAINER_PREFIX + localId;
- IMountService ms = getMs();
- return ms.isSecureContainerMounted(fullId);
+ IStorageManager sm = getSm();
+ return sm.isSecureContainerMounted(fullId);
}
- private IMountService getMs() {
+ private IStorageManager getSm() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
- return IMountService.Stub.asInterface(service);
+ return IStorageManager.Stub.asInterface(service);
} else {
- Log.e(TAG, "Can't get mount service");
+ Log.e(TAG, "Can't get storagemanager service");
}
return null;
}
private boolean isMediaMounted() throws Exception {
String mPath = Environment.getExternalStorageDirectory().toString();
- String state = getMs().getVolumeState(mPath);
+ String state = getSm().getVolumeState(mPath);
return Environment.MEDIA_MOUNTED.equals(state);
}
@@ -385,11 +385,11 @@
return;
}
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true));
- String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX
+ String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
+ "testUnmountBusyContainer");
File f = new File(path, "reference");
@@ -408,12 +408,12 @@
return;
}
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true));
- String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX
+ String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
+ "testDestroyBusyContainer");
File f = new File(path, "reference");
@@ -480,10 +480,10 @@
return;
}
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testContainerSize", 1, "none", FS_FAT, true));
- String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize");
+ String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize");
byte[] buf = new byte[4096];
File f = new File(path, "reference");
@@ -495,9 +495,9 @@
}
public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception {
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
assertNull("Getting the path for an invalid container should return null",
- ms.getSecureContainerPath("jparks.broke.it"));
+ sm.getSecureContainerPath("jparks.broke.it"));
}
/*------------ Tests for unmounting volume ---*/
@@ -506,7 +506,7 @@
boolean getMediaState() throws Exception {
String mPath = Environment.getExternalStorageDirectory().toString();
- String state = getMs().getVolumeState(mPath);
+ String state = getSm().getVolumeState(mPath);
return Environment.MEDIA_MOUNTED.equals(state);
}
@@ -520,7 +520,7 @@
}
String mPath = Environment.getExternalStorageDirectory().toString();
- int ret = getMs().mountVolume(mPath);
+ int ret = getSm().mountVolume(mPath);
return ret == StorageResultCode.OperationSucceeded;
}
@@ -567,7 +567,7 @@
try {
// Wait on observer
synchronized(observer) {
- getMs().unmountVolume(path, false, false);
+ getSm().unmountVolume(path, false, false);
long waitTime = 0;
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
observer.wait(WAIT_TIME_INCR);
@@ -634,7 +634,7 @@
// Wait on observer
synchronized(observer) {
for (int i = 0; i < 5; i++) {
- getMs().unmountVolume(path, false, false);
+ getSm().unmountVolume(path, false, false);
}
long waitTime = 0;
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
@@ -661,7 +661,7 @@
}
}
- class ShutdownObserver extends IMountShutdownObserver.Stub{
+ class ShutdownObserver extends IStorageShutdownObserver.Stub{
private boolean doneFlag = false;
int statusCode;
@@ -683,10 +683,10 @@
}
void invokeShutdown() throws Exception {
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
ShutdownObserver observer = new ShutdownObserver();
synchronized (observer) {
- ms.shutdown(observer);
+ sm.shutdown(observer);
}
}
@@ -731,12 +731,12 @@
if (!getMediaState()) {
mountMedia();
}
- IMountService ms = getMs();
+ IStorageManager sm = getSm();
ShutdownObserver observer = new ShutdownObserver();
synchronized (observer) {
- ms.shutdown(observer);
+ sm.shutdown(observer);
for (int i = 0; i < 4; i++) {
- ms.shutdown(null);
+ sm.shutdown(null);
}
}
} finally {
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 7ba46be..b6b0e68 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -20,11 +20,13 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
import android.os.Parcel;
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 com.android.frameworks.coretests.R;
@@ -38,6 +40,10 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for RemoteViews.
*/
@@ -166,4 +172,164 @@
parcel.recycle();
return size;
}
+
+ @Test
+ public void asyncApply_fail() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_test_bad_1);
+ ViewAppliedListener listener = new ViewAppliedListener();
+ views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+
+ boolean exceptionThrown = false;
+ try {
+ listener.waitAndGetView();
+ } catch (Exception e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ }
+
+ @Test
+ public void asyncApply() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+ views.setTextViewText(R.id.text, "Dummy");
+
+ View syncView = views.apply(mContext, mContainer);
+
+ ViewAppliedListener listener = new ViewAppliedListener();
+ views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+ View asyncView = listener.waitAndGetView();
+
+ verifyViewTree(syncView, asyncView, "Dummy");
+ }
+
+ @Test
+ public void asyncApply_viewStub() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
+ views.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_views_text);
+ // This will cause the view to be inflated
+ views.setViewVisibility(R.id.viewStub, View.INVISIBLE);
+ views.setTextViewText(R.id.stub_inflated, "Dummy");
+
+ View syncView = views.apply(mContext, mContainer);
+
+ ViewAppliedListener listener = new ViewAppliedListener();
+ views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+ View asyncView = listener.waitAndGetView();
+
+ verifyViewTree(syncView, asyncView, "Dummy");
+ }
+
+ @Test
+ public void asyncApply_nestedViews() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
+ views.removeAllViews(R.id.container);
+ views.addView(R.id.container, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
+ views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
+ views.addView(R.id.container, createViewChained(2, "row3-c1", "row3-c2"));
+
+ View syncView = views.apply(mContext, mContainer);
+
+ ViewAppliedListener listener = new ViewAppliedListener();
+ views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+ View asyncView = listener.waitAndGetView();
+
+ verifyViewTree(syncView, asyncView,
+ "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2", "row3-c1", "row3-c2");
+ }
+
+ @Test
+ public void asyncApply_viewstub_nestedViews() throws Exception {
+ RemoteViews viewstub = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
+ viewstub.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_view_host);
+ // This will cause the view to be inflated
+ viewstub.setViewVisibility(R.id.viewStub, View.INVISIBLE);
+ viewstub.addView(R.id.stub_inflated, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
+
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
+ views.removeAllViews(R.id.container);
+ views.addView(R.id.container, viewstub);
+ views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
+
+ View syncView = views.apply(mContext, mContainer);
+
+ ViewAppliedListener listener = new ViewAppliedListener();
+ views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
+ View asyncView = listener.waitAndGetView();
+
+ verifyViewTree(syncView, asyncView, "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2");
+ }
+
+ private RemoteViews createViewChained(int depth, String... texts) {
+ RemoteViews result = new RemoteViews(mPackage, R.layout.remote_view_host);
+
+ // Create depth
+ RemoteViews parent = result;
+ while(depth > 0) {
+ depth--;
+ RemoteViews child = new RemoteViews(mPackage, R.layout.remote_view_host);
+ parent.addView(R.id.container, child);
+ parent = child;
+ }
+
+ // Add texts
+ for (String text : texts) {
+ RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_text);
+ child.setTextViewText(R.id.text, text);
+ parent.addView(R.id.container, child);
+ }
+ return result;
+ }
+
+ private void verifyViewTree(View v1, View v2, String... texts) {
+ ArrayList<String> expectedTexts = new ArrayList<>(Arrays.asList(texts));
+ verifyViewTreeRecur(v1, v2, expectedTexts);
+ // Verify that all expected texts were found
+ assertEquals(0, expectedTexts.size());
+ }
+
+ private void verifyViewTreeRecur(View v1, View v2, ArrayList<String> expectedTexts) {
+ assertEquals(v1.getClass(), v2.getClass());
+
+ if (v1 instanceof TextView) {
+ String text = ((TextView) v1).getText().toString();
+ assertEquals(text, ((TextView) v2).getText().toString());
+ // Verify that the text was one of the expected texts and remove it from the list
+ assertTrue(expectedTexts.remove(text));
+ } else if (v1 instanceof ViewGroup) {
+ ViewGroup vg1 = (ViewGroup) v1;
+ ViewGroup vg2 = (ViewGroup) v2;
+ assertEquals(vg1.getChildCount(), vg2.getChildCount());
+ for (int i = vg1.getChildCount() - 1; i >= 0; i--) {
+ verifyViewTreeRecur(vg1.getChildAt(i), vg2.getChildAt(i), expectedTexts);
+ }
+ }
+ }
+
+ private class ViewAppliedListener implements RemoteViews.OnViewAppliedListener {
+
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+ private View mView;
+ private Exception mError;
+
+ @Override
+ public void onViewApplied(View v) {
+ mView = v;
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onError(Exception e) {
+ mError = e;
+ mLatch.countDown();
+ }
+
+ public View waitAndGetView() throws Exception {
+ mLatch.await();
+
+ if (mError != null) {
+ throw new Exception(mError);
+ }
+ return mView;
+ }
+ }
}
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index 134ac0c..6718259 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -18,30 +18,17 @@
########################
include $(CLEAR_VARS)
-
LOCAL_MODULE := platform.xml
-
LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
include $(BUILD_PREBUILT)
########################
-#include $(CLEAR_VARS)
+include $(CLEAR_VARS)
+LOCAL_MODULE := privapp-permissions-platform.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
-#LOCAL_MODULE := required_hardware.xml
-
-#LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-#LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-#LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-#include $(BUILD_PREBUILT)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
new file mode 100644
index 0000000..3fc7914
--- /dev/null
+++ b/data/etc/privapp-permissions-platform.xml
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!--
+This XML file declares which signature|privileged permissions should be granted to privileged
+applications that come with the platform
+-->
+<permissions>
+ <privapp-permissions package="com.android.backupconfirm">
+ <permission name="android.permission.BACKUP"/>
+ <permission name="android.permission.CRYPT_KEEPER"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.cellbroadcastreceiver">
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.contacts">
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.defcontainer">
+ <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.dialer">
+ <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/>
+ <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+ <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.emergency">
+ <permission name="android.permission.MANAGE_USERS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.externalstorage">
+ <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.launcher">
+ <permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.location.fused">
+ <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.managedprovisioning">
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CRYPT_KEEPER"/>
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.INSTALL_PACKAGES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
+ <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+ <permission name="android.permission.SET_TIME"/>
+ <permission name="android.permission.SET_TIME_ZONE"/>
+ <permission name="android.permission.SHUTDOWN"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.mms.service">
+ <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
+ <permission name="android.permission.BIND_CARRIER_SERVICES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.mtp">
+ <permission name="android.permission.MANAGE_USB"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.musicfx">
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.packageinstaller">
+ <permission name="android.permission.CLEAR_APP_CACHE"/>
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.INSTALL_PACKAGES"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.phone">
+ <permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/>
+ <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
+ <permission name="android.permission.BIND_CARRIER_SERVICES"/>
+ <permission name="android.permission.CALL_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.DUMP"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+ <permission name="android.permission.REBOOT"/>
+ <permission name="android.permission.REGISTER_CALL_PROVIDER"/>
+ <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
+ <permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/>
+ <permission name="android.permission.SET_TIME"/>
+ <permission name="android.permission.SET_TIME_ZONE"/>
+ <permission name="android.permission.SHUTDOWN"/>
+ <permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ <permission name="android.permission.UPDATE_LOCK"/>
+ <permission name="android.permission.WRITE_APN_SETTINGS"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+ <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.providers.calendar">
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.providers.contacts">
+ <permission name="android.permission.BIND_DIRECTORY_SEARCH"/>
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.providers.downloads">
+ <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
+ <permission name="android.permission.CLEAR_APP_CACHE"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.providers.media">
+ <permission name="android.permission.ACCESS_MTP"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.providers.telephony">
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.provision">
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.server.telecom">
+ <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
+ <permission name="android.permission.BIND_INCALL_SERVICE"/>
+ <permission name="android.permission.CALL_PRIVILEGED"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.settings">
+ <permission name="android.permission.ACCESS_CHECKIN_PROPERTIES"/>
+ <permission name="android.permission.ACCESS_NOTIFICATIONS"/>
+ <permission name="android.permission.BACKUP"/>
+ <permission name="android.permission.BATTERY_STATS"/>
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.FORCE_STOP_PACKAGES"/>
+ <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
+ <permission name="android.permission.MANAGE_FINGERPRINT"/>
+ <permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
+ <permission name="android.permission.MOVE_PACKAGE"/>
+ <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+ <permission name="android.permission.REBOOT"/>
+ <permission name="android.permission.SET_TIME"/>
+ <permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.USER_ACTIVITY"/>
+ <permission name="android.permission.WRITE_APN_SETTINGS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.sharedstoragebackup">
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.shell">
+ <permission name="android.permission.BACKUP"/>
+ <permission name="android.permission.BATTERY_STATS"/>
+ <permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <permission name="android.permission.CHANGE_CONFIGURATION"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.DELETE_CACHE_FILES"/>
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.DUMP"/>
+ <permission name="android.permission.FORCE_STOP_PACKAGES"/>
+ <permission name="android.permission.GET_APP_OPS_STATS"/>
+ <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
+ <permission name="android.permission.INSTALL_PACKAGES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/>
+ <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
+ <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
+ <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
+ <permission name="android.permission.MOVE_PACKAGE"/>
+ <permission name="android.permission.READ_FRAME_BUFFER"/>
+ <permission name="android.permission.REAL_GET_TASKS"/>
+ <permission name="android.permission.REGISTER_CALL_PROVIDER"/>
+ <permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
+ <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
+ <permission name="android.permission.RETRIEVE_WINDOW_CONTENT"/>
+ <permission name="android.permission.SET_ALWAYS_FINISH"/>
+ <permission name="android.permission.SET_ANIMATION_SCALE"/>
+ <permission name="android.permission.SET_DEBUG_APP"/>
+ <permission name="android.permission.SET_PROCESS_LIMIT"/>
+ <permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.statementservice">
+ <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.storagemanager">
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.systemui">
+ <permission name="android.permission.BATTERY_STATS"/>
+ <permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONTROL_VPN"/>
+ <permission name="android.permission.DUMP"/>
+ <permission name="android.permission.GET_APP_OPS_STATS"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/>
+ <permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
+ <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
+ <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+ <permission name="android.permission.READ_DREAM_STATE"/>
+ <permission name="android.permission.READ_FRAME_BUFFER"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.REAL_GET_TASKS"/>
+ <permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
+ <permission name="android.permission.START_TASKS_FROM_RECENTS"/>
+ <permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.WRITE_DREAM_STATE"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+
+ <privapp-permissions package="com.android.vpndialogs">
+ <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONTROL_VPN"/>
+ </privapp-permissions>
+
+</permissions>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index 619fd26..b51e6d9 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -390,7 +390,9 @@
<dd>The package part of the component name, as per the {@link
android.content.Intent#setComponent setComponent()} method.</dd>
</dl>
-
+<p class="note"><strong>Note: </strong>You must use string literals as the values for these
+intent attributes. You cannot use resource strings, such as <code>@string/foo</code>, to define the attributes.
+</p>
<h2 id="Activity">Creating a Preference Activity</h2>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 79c63ee..e628cf8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1241,6 +1241,11 @@
* #getAllocationByteCount()}.</p>
*/
public final int getByteCount() {
+ if (mRecycled) {
+ Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
+ + "This is undefined behavior!");
+ return 0;
+ }
// int result permits bitmaps up to 46,340 x 46,340
return getRowBytes() * getHeight();
}
@@ -1260,6 +1265,11 @@
* @see #reconfigure(int, int, Config)
*/
public final int getAllocationByteCount() {
+ if (mRecycled) {
+ Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
+ + "This is undefined behavior!");
+ return 0;
+ }
return nativeGetAllocationByteCount(mNativePtr);
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 4fc7892..e566b9d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
@@ -413,6 +414,9 @@
if (alias == null) {
throw new NullPointerException("alias == null");
}
+ if (context == null) {
+ throw new NullPointerException("context == null");
+ }
final String keyId;
try (KeyChainConnection keyChainConnection = bind(context.getApplicationContext())) {
@@ -630,7 +634,7 @@
if (!mConnectedAtLeastOnce) {
mConnectedAtLeastOnce = true;
try {
- q.put(IKeyChainService.Stub.asInterface(service));
+ q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
} catch (InterruptedException e) {
// will never happen, since the queue starts with one available slot
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8dc502a..4722050 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -40,6 +40,7 @@
renderthread/OpenGLPipeline.cpp \
renderthread/DrawFrameTask.cpp \
renderthread/EglManager.cpp \
+ renderthread/VulkanManager.cpp \
renderthread/RenderProxy.cpp \
renderthread/RenderTask.cpp \
renderthread/RenderThread.cpp \
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e410d71..9c4cb09 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -133,7 +133,7 @@
// Shaders
bool hasBitmap;
- bool isBitmapNpot;
+ bool useShaderBasedWrap;
bool hasVertexAlpha;
bool useShadowAlphaInterp;
@@ -180,7 +180,7 @@
modulate = false;
hasBitmap = false;
- isBitmapNpot = false;
+ useShaderBasedWrap = false;
hasGradient = false;
gradientType = kGradientLinear;
@@ -234,7 +234,7 @@
if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
if (hasBitmap) {
key |= PROGRAM_KEY_BITMAP;
- if (isBitmapNpot) {
+ if (useShaderBasedWrap) {
key |= PROGRAM_KEY_BITMAP_NPOT;
key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 1afc978..0c2309f 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -707,7 +707,7 @@
if (blendFramebuffer) {
generateBlend(shader, "blendFramebuffer", description.framebufferMode);
}
- if (description.isBitmapNpot) {
+ if (description.useShaderBasedWrap) {
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
}
if (description.hasGradient) {
@@ -736,7 +736,7 @@
shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
}
if (description.hasBitmap) {
- if (!description.isBitmapNpot) {
+ if (!description.useShaderBasedWrap) {
shader.append(gFS_Main_FetchBitmap);
} else {
shader.append(gFS_Main_FetchBitmapNpot);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7c97e77..5e21dfc 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -738,7 +738,7 @@
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
const int N = end - start;
- SkAutoSMalloc<1024> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
+ SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
SkRSXform* xform = (SkRSXform*)storage.get();
uint16_t* glyphs = (uint16_t*)(xform + N);
SkPathMeasure meas(path, false);
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 971c2a3..34e6a06 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -58,7 +58,7 @@
}
static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
- caches->textureState().bindTexture(texture->id());
+ caches->textureState().bindTexture(texture->target(), texture->id());
texture->setWrapST(wrapS, wrapT);
}
@@ -218,10 +218,13 @@
const float height = outData->bitmapTexture->height();
description->hasBitmap = true;
- if (!caches.extensions().hasNPot()
+ // gralloc doesn't support non-clamp modes
+ if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot()
&& (!isPowerOfTwo(width) || !isPowerOfTwo(height))
- && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode)) {
- description->isBitmapNpot = true;
+ && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
+ // need non-clamp mode, but it's not supported for this draw,
+ // so enable custom shader logic to mimic
+ description->useShaderBasedWrap = true;
description->bitmapWrapS = gTileModes[xy[0]];
description->bitmapWrapT = gTileModes[xy[1]];
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index b8f7d9f..c028f115 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -227,7 +227,7 @@
PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
status_t error;
sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER
+ 1, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER
| GraphicBuffer::USAGE_SW_READ_NEVER , &error);
if (!buffer.get()) {
@@ -413,7 +413,6 @@
case PixelStorageType::Heap:
return mPixelStorage.heap.address;
case PixelStorageType::Hardware:
- LOG_ALWAYS_FATAL_IF("Can't get address for hardware bitmap");
return nullptr;
}
}
@@ -470,6 +469,12 @@
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
}
+void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
+ outBitmap->setInfo(info(), rowBytes());
+ outBitmap->setPixelRef(this);
+ outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
+}
+
void Bitmap::getBounds(SkRect* bounds) const {
SkASSERT(bounds);
bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3940381..663238c 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -85,6 +85,10 @@
void getSkBitmap(SkBitmap* outBitmap);
+ // Ugly hack: in case of hardware bitmaps, it sets nullptr as pixels pointer
+ // so it would crash if anyone tries to render this bitmap.
+ void getSkBitmapForShaders(SkBitmap* outBitmap);
+
int getAshmemFd() const;
size_t getAllocationByteCount() const;
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 50bc6c3..f95d98c 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -114,4 +114,27 @@
gDefaultTypeface = face;
}
+void Typeface::setRobotoTypefaceForTest() {
+ const char* kRobotoFont = "/system/fonts/Roboto-Regular.ttf";
+ sk_sp<SkTypeface> typeface = SkTypeface::MakeFromFile(kRobotoFont);
+ LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
+
+ minikin::FontFamily* family = new minikin::FontFamily();
+ minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), nullptr, 0, 0);
+ family->addFont(font);
+ font->Unref();
+
+ std::vector<minikin::FontFamily*> typefaces = { family };
+ minikin::FontCollection *collection = new minikin::FontCollection(typefaces);
+ family->Unref();
+
+ Typeface* hwTypeface = new Typeface();
+ hwTypeface->fFontCollection = collection;
+ hwTypeface->fSkiaStyle = SkTypeface::kNormal;
+ hwTypeface->fBaseWeight = 400;
+ hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
+
+ Typeface::setDefault(hwTypeface);
+}
+
}
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index ed0a7ebd..1be630c 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -48,6 +48,9 @@
static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);
static void setDefault(Typeface* face);
+
+ // Sets roboto font as the default typeface for testing purpose.
+ static void setRobotoTypefaceForTest();
};
}
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index dca78b3..37126a6 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -18,6 +18,7 @@
libutils \
libEGL \
libGLESv2 \
+ libvulkan \
libskia \
libui \
libgui \
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index accbabd..7dcbbd0 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -164,6 +164,14 @@
paint = &tmpPaint;
}
renderNode->getLayerSurface()->draw(canvas, 0, 0, paint);
+
+ if (CC_UNLIKELY(Properties::debugLayersUpdates
+ && !renderNode->getSkiaLayer()->hasRenderedSinceRepaint)) {
+ renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
+ SkPaint layerPaint;
+ layerPaint.setColor(0x7f00ff00);
+ canvas->drawRect(bounds, layerPaint);
+ }
// composing a software layer with alpha
} else if (properties.effectiveLayerType() == LayerType::Software) {
SkPaint paint;
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index a204d5c..6973209 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -215,7 +215,7 @@
static void DrawRRectShadows(const SkRect& casterRect, SkScalar casterCornerRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterAlpha, SkScalar casterZValue,
SkScalar scaleFactor, SkCanvas* canvas) {
- SkASSERT(cornerRadius >= 0.0f);
+ SkASSERT(casterCornerRadius >= 0.0f);
// For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
const SkScalar minRadius = 0.5f / scaleFactor;
@@ -387,7 +387,7 @@
static void DrawRRectShadowsWithClip(const SkRect& casterRect, SkScalar casterCornerRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkScalar casterZValue, SkScalar scaleFactor,
const SkRRect& clipRR, SkCanvas* canvas) {
- SkASSERT(cornerRadius >= 0.0f);
+ SkASSERT(casterCornerRadius >= 0.0f);
const bool isOval = casterCornerRadius >= std::max(SkScalarHalf(casterRect.width()),
SkScalarHalf(casterRect.height()));
diff --git a/libs/hwui/pipeline/skia/SkiaLayer.h b/libs/hwui/pipeline/skia/SkiaLayer.h
index 0988d7e..904d57e0 100644
--- a/libs/hwui/pipeline/skia/SkiaLayer.h
+++ b/libs/hwui/pipeline/skia/SkiaLayer.h
@@ -30,6 +30,7 @@
{
sk_sp<SkSurface> layerSurface;
Matrix4 inverseTransformInWindow;
+ bool hasRenderedSinceRepaint = false;
};
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a6612c9..a4a83ef 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -106,6 +106,7 @@
return;
}
+ layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
layerCanvas->clear(SK_ColorTRANSPARENT);
RenderNodeDrawable root(layerNode, layerCanvas, false);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ba13ca58..ca394b2 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -23,37 +23,43 @@
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
+#include <SkSurface.h>
#include <SkTypes.h>
-#include <WindowContextFactory_android.h>
-#include <VulkanWindowContext.h>
+
+#include <GrContext.h>
+#include <GrTypes.h>
+#include <vk/GrVkTypes.h>
#include <android/native_window.h>
#include <cutils/properties.h>
#include <strings.h>
using namespace android::uirenderer::renderthread;
-using namespace sk_app;
namespace android {
namespace uirenderer {
namespace skiapipeline {
+SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread)
+ : SkiaPipeline(thread)
+ , mVkManager(thread.vulkanManager()) {}
+
MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
- return (mWindowContext != nullptr) ?
- MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
+ return MakeCurrentResult::AlreadyCurrent;
}
Frame SkiaVulkanPipeline::getFrame() {
- LOG_ALWAYS_FATAL_IF(mWindowContext == nullptr, "Tried to draw into null vulkan context!");
- mBackbuffer = mWindowContext->getBackbufferSurface();
- if (mBackbuffer.get() == nullptr) {
- // try recreating the context?
+ LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
+ "drawRenderNode called on a context with no surface!");
+
+ SkSurface* backBuffer = mVkManager.getBackbufferSurface(mVkSurface);
+ if (backBuffer == nullptr) {
SkDebugf("failed to get backbuffer");
return Frame(-1, -1, 0);
}
// TODO: support buffer age if Vulkan API can do it
- Frame frame(mBackbuffer->width(), mBackbuffer->height(), 0);
+ Frame frame(backBuffer->width(), backBuffer->height(), 0);
return frame;
}
@@ -66,16 +72,18 @@
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
- if (mBackbuffer.get() == nullptr) {
+ sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
+ if (backBuffer.get() == nullptr) {
return false;
}
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, mBackbuffer);
+ SkiaPipeline::updateLighting(lightGeometry, lightInfo);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
layerUpdateQueue->clear();
// Draw visual debugging features
if (CC_UNLIKELY(Properties::showDirtyRegions
|| ProfileType::None != Properties::getProfileType())) {
- SkCanvas* profileCanvas = mBackbuffer->getCanvas();
+ SkCanvas* profileCanvas = backBuffer->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
profileCanvas->flush();
@@ -99,11 +107,9 @@
currentFrameInfo->markSwapBuffers();
if (*requireSwap) {
- mWindowContext->swapBuffers();
+ mVkManager.swapBuffers(mVkSurface);
}
- mBackbuffer.reset();
-
return *requireSwap;
}
@@ -113,6 +119,7 @@
}
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
+ mVkManager.initialize();
Layer* layer = new Layer(mRenderThread.renderState(), 0, 0);
return new DeferredLayerUpdater(layer);
}
@@ -121,33 +128,24 @@
}
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
-
- if (mWindowContext) {
- delete mWindowContext;
- mWindowContext = nullptr;
+ if (mVkSurface) {
+ mVkManager.destroySurface(mVkSurface);
+ mVkSurface = nullptr;
}
if (surface) {
- DisplayParams displayParams;
- mWindowContext = window_context_factory::NewVulkanForAndroid(surface, displayParams);
- if (mWindowContext) {
- DeviceInfo::initialize(mWindowContext->getGrContext()->caps()->maxRenderTargetSize());
- }
+ mVkSurface = mVkManager.createSurface(surface);
}
-
- // this doesn't work for if there is more than one CanvasContext available at one time!
- mRenderThread.setGrContext(mWindowContext ? mWindowContext->getGrContext() : nullptr);
-
- return mWindowContext != nullptr;
+ return mVkSurface != nullptr;
}
bool SkiaVulkanPipeline::isSurfaceReady() {
- return CC_LIKELY(mWindowContext != nullptr) && mWindowContext->isValid();
+ return CC_UNLIKELY(mVkSurface != nullptr);
}
bool SkiaVulkanPipeline::isContextReady() {
- return CC_LIKELY(mWindowContext != nullptr);
+ return CC_LIKELY(mVkManager.hasVkContext());
}
void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index cdc8692..aab1d7a 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -17,11 +17,7 @@
#pragma once
#include "SkiaPipeline.h"
-#include <SkSurface.h>
-
-namespace sk_app {
-class WindowContext;
-}
+#include "renderthread/VulkanManager.h"
namespace android {
namespace uirenderer {
@@ -29,7 +25,7 @@
class SkiaVulkanPipeline : public SkiaPipeline {
public:
- SkiaVulkanPipeline(renderthread::RenderThread& thread) : SkiaPipeline(thread) {}
+ SkiaVulkanPipeline(renderthread::RenderThread& thread);
virtual ~SkiaVulkanPipeline() {}
renderthread::MakeCurrentResult makeCurrent() override;
@@ -53,8 +49,8 @@
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
private:
- sk_app::WindowContext* mWindowContext = nullptr;
- sk_sp<SkSurface> mBackbuffer;
+ renderthread::VulkanManager& mVkManager;
+ renderthread::VulkanSurface* mVkSurface = nullptr;
};
} /* namespace skiapipeline */
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9688340..f3789c8 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -20,6 +20,7 @@
#include "CanvasContext.h"
#include "EglManager.h"
#include "RenderProxy.h"
+#include "VulkanManager.h"
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
@@ -157,7 +158,8 @@
, mFrameCallbackTaskPending(false)
, mFrameCallbackTask(nullptr)
, mRenderState(nullptr)
- , mEglManager(nullptr) {
+ , mEglManager(nullptr)
+ , mVkManager(nullptr) {
Properties::load();
mFrameCallbackTask = new DispatchFrameCallbacks(this);
mLooper = new Looper(false);
@@ -191,6 +193,7 @@
mEglManager = new EglManager(*this);
mRenderState = new RenderState(*this);
mJankTracker = new JankTracker(mDisplayInfo);
+ mVkManager = new VulkanManager(*this);
}
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index d8677e13..12050dd 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -46,6 +46,7 @@
class DispatchFrameCallbacks;
class EglManager;
class RenderProxy;
+class VulkanManager;
class TaskQueue {
public:
@@ -98,6 +99,8 @@
GrContext* getGrContext() const { return mGrContext.get(); }
void setGrContext(GrContext* cxt) { mGrContext.reset(cxt); }
+ VulkanManager& vulkanManager() { return *mVkManager; }
+
protected:
virtual bool threadLoop() override;
@@ -150,6 +153,7 @@
JankTracker* mJankTracker = nullptr;
sk_sp<GrContext> mGrContext;
+ VulkanManager* mVkManager;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
new file mode 100644
index 0000000..4d239bc
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VulkanManager.h"
+
+#include "DeviceInfo.h"
+#include "RenderThread.h"
+
+#include <GrContext.h>
+#include <GrTypes.h>
+#include <vk/GrVkTypes.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
+#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
+
+VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
+}
+
+void VulkanManager::destroy() {
+ if (!hasVkContext()) return;
+
+ if (VK_NULL_HANDLE != mCommandPool) {
+ mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
+ mCommandPool = VK_NULL_HANDLE;
+ }
+}
+
+void VulkanManager::initialize() {
+ if (hasVkContext()) { return; }
+
+ auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
+
+ mBackendContext.reset(GrVkBackendContext::Create(&mPresentQueueIndex, canPresent));
+
+ // Get all the addresses of needed vulkan functions
+ VkInstance instance = mBackendContext->fInstance;
+ VkDevice device = mBackendContext->fDevice;
+ GET_PROC(CreateAndroidSurfaceKHR);
+ GET_PROC(DestroySurfaceKHR);
+ GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
+ GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
+ GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
+ GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
+ GET_DEV_PROC(CreateSwapchainKHR);
+ GET_DEV_PROC(DestroySwapchainKHR);
+ GET_DEV_PROC(GetSwapchainImagesKHR);
+ GET_DEV_PROC(AcquireNextImageKHR);
+ GET_DEV_PROC(QueuePresentKHR);
+ GET_DEV_PROC(CreateCommandPool);
+ GET_DEV_PROC(DestroyCommandPool);
+ GET_DEV_PROC(AllocateCommandBuffers);
+ GET_DEV_PROC(FreeCommandBuffers);
+ GET_DEV_PROC(ResetCommandBuffer);
+ GET_DEV_PROC(BeginCommandBuffer);
+ GET_DEV_PROC(EndCommandBuffer);
+ GET_DEV_PROC(CmdPipelineBarrier);
+ GET_DEV_PROC(GetDeviceQueue);
+ GET_DEV_PROC(QueueSubmit);
+ GET_DEV_PROC(QueueWaitIdle);
+ GET_DEV_PROC(DeviceWaitIdle);
+ GET_DEV_PROC(CreateSemaphore);
+ GET_DEV_PROC(DestroySemaphore);
+ GET_DEV_PROC(CreateFence);
+ GET_DEV_PROC(DestroyFence);
+ GET_DEV_PROC(WaitForFences);
+ GET_DEV_PROC(ResetFences);
+
+ // create the command pool for the command buffers
+ if (VK_NULL_HANDLE == mCommandPool) {
+ VkCommandPoolCreateInfo commandPoolInfo;
+ memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
+ commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ // this needs to be on the render queue
+ commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
+ commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+ SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice,
+ &commandPoolInfo, nullptr, &mCommandPool);
+ SkASSERT(VK_SUCCESS == res);
+ }
+
+ mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
+
+ mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
+ (GrBackendContext) mBackendContext.get()));
+ DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
+}
+
+// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
+// previous uses have finished before returning.
+VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
+ SkASSERT(surface->mBackbuffers);
+
+ ++surface->mCurrentBackbufferIndex;
+ if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
+ surface->mCurrentBackbufferIndex = 0;
+ }
+
+ VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
+ surface->mCurrentBackbufferIndex;
+
+ // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
+ // reuse its commands buffers.
+ VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences,
+ true, UINT64_MAX);
+ if (res != VK_SUCCESS) {
+ return nullptr;
+ }
+
+ return backbuffer;
+}
+
+
+SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
+ VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
+ SkASSERT(backbuffer);
+
+ VkResult res;
+
+ res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
+ SkASSERT(VK_SUCCESS == res);
+
+ // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
+ // finished presenting and that it is safe to begin sending new commands to the returned image.
+ res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+
+ if (VK_ERROR_SURFACE_LOST_KHR == res) {
+ // need to figure out how to create a new vkSurface without the platformData*
+ // maybe use attach somehow? but need a Window
+ return nullptr;
+ }
+ if (VK_ERROR_OUT_OF_DATE_KHR == res) {
+ // tear swapchain down and try again
+ if (!createSwapchain(surface)) {
+ return nullptr;
+ }
+
+ // acquire the image
+ res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+
+ if (VK_SUCCESS != res) {
+ return nullptr;
+ }
+ }
+
+ // set up layout transfer from initial to color attachment
+ VkImageLayout layout = surface->mImageLayouts[backbuffer->mImageIndex];
+ SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
+ VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
+ 0 : VK_ACCESS_MEMORY_READ_BIT;
+ VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ VkImageMemoryBarrier imageMemoryBarrier = {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
+ mPresentQueueIndex, // srcQueueFamilyIndex
+ mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ };
+ mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
+
+ VkCommandBufferBeginInfo info;
+ memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
+ info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ info.flags = 0;
+ mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
+
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0,
+ 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+
+ mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
+
+ VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ // insert the layout transfer into the queue and wait on the acquire
+ VkSubmitInfo submitInfo;
+ memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.waitSemaphoreCount = 1;
+ // Wait to make sure aquire semaphore set above has signaled.
+ submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
+ submitInfo.pWaitDstStageMask = &waitDstStageFlags;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
+ submitInfo.signalSemaphoreCount = 0;
+
+ // Attach first fence to submission here so we can track when the command buffer finishes.
+ mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
+
+ // We need to notify Skia that we changed the layout of the wrapped VkImage
+ GrVkImageInfo* imageInfo;
+ sk_sp<SkSurface> skSurface = surface->mSurfaces[backbuffer->mImageIndex];
+ skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
+ SkSurface::kFlushRead_BackendHandleAccess);
+ imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ surface->mBackbuffer = std::move(skSurface);
+ return surface->mBackbuffer.get();
+}
+
+void VulkanManager::destroyBuffers(VulkanSurface* surface) {
+ if (surface->mBackbuffers) {
+ for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
+ mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
+ UINT64_MAX);
+ surface->mBackbuffers[i].mImageIndex = -1;
+ mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
+ nullptr);
+ mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
+ nullptr);
+ mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
+ mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
+ mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
+ }
+ }
+
+ delete[] surface->mBackbuffers;
+ surface->mBackbuffers = nullptr;
+ delete[] surface->mSurfaces;
+ surface->mSurfaces = nullptr;
+ delete[] surface->mImageLayouts;
+ surface->mImageLayouts = nullptr;
+ delete[] surface->mImages;
+ surface->mImages = nullptr;
+}
+
+void VulkanManager::destroySurface(VulkanSurface* surface) {
+ // Make sure all submit commands have finished before starting to destroy objects.
+ if (VK_NULL_HANDLE != mPresentQueue) {
+ mQueueWaitIdle(mPresentQueue);
+ }
+ mDeviceWaitIdle(mBackendContext->fDevice);
+
+ destroyBuffers(surface);
+
+ if (VK_NULL_HANDLE != surface->mSwapchain) {
+ mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr);
+ surface->mSwapchain = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != surface->mVkSurface) {
+ mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr);
+ surface->mVkSurface = VK_NULL_HANDLE;
+ }
+ delete surface;
+}
+
+void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
+ mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
+ nullptr);
+ SkASSERT(surface->mImageCount);
+ surface->mImages = new VkImage[surface->mImageCount];
+ mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain,
+ &surface->mImageCount, surface->mImages);
+
+ SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+
+ bool wantSRGB = VK_FORMAT_R8G8B8A8_SRGB == format;
+ GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
+
+ // set up initial image layouts and create surfaces
+ surface->mImageLayouts = new VkImageLayout[surface->mImageCount];
+ surface->mSurfaces = new sk_sp<SkSurface>[surface->mImageCount];
+ for (uint32_t i = 0; i < surface->mImageCount; ++i) {
+ GrBackendRenderTargetDesc desc;
+ GrVkImageInfo info;
+ info.fImage = surface->mImages[i];
+ info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+ info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+ info.fFormat = format;
+ info.fLevelCount = 1;
+
+ desc.fWidth = extent.width;
+ desc.fHeight = extent.height;
+ desc.fConfig = config;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fSampleCnt = 0;
+ desc.fStencilBits = 0;
+ desc.fRenderTargetHandle = (GrBackendObject) &info;
+
+ surface->mSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
+ desc, &props);
+ surface->mImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ SkASSERT(mCommandPool != VK_NULL_HANDLE);
+
+ // set up the backbuffers
+ VkSemaphoreCreateInfo semaphoreInfo;
+ memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+ VkCommandBufferAllocateInfo commandBuffersInfo;
+ memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
+ commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ commandBuffersInfo.pNext = nullptr;
+ commandBuffersInfo.commandPool = mCommandPool;
+ commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ commandBuffersInfo.commandBufferCount = 2;
+ VkFenceCreateInfo fenceInfo;
+ memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fenceInfo.pNext = nullptr;
+ fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+ // we create one additional backbuffer structure here, because we want to
+ // give the command buffers they contain a chance to finish before we cycle back
+ surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
+ for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
+ SkDEBUGCODE(VkResult res);
+ surface->mBackbuffers[i].mImageIndex = -1;
+ SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mAcquireSemaphore);
+ SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mRenderSemaphore);
+ SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
+ SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[0]);
+ SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[1]);
+ SkASSERT(VK_SUCCESS == res);
+ }
+ surface->mCurrentBackbufferIndex = surface->mImageCount;
+}
+
+bool VulkanManager::createSwapchain(VulkanSurface* surface) {
+ // check for capabilities
+ VkSurfaceCapabilitiesKHR caps;
+ VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
+ surface->mVkSurface, &caps);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ uint32_t surfaceFormatCount;
+ res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+ &surfaceFormatCount, nullptr);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
+ VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
+ res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
+ &surfaceFormatCount, surfaceFormats);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ uint32_t presentModeCount;
+ res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+ surface->mVkSurface, &presentModeCount, nullptr);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
+ VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
+ res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
+ surface->mVkSurface, &presentModeCount, presentModes);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ VkExtent2D extent = caps.currentExtent;
+ // clamp width; to handle currentExtent of -1 and protect us from broken hints
+ if (extent.width < caps.minImageExtent.width) {
+ extent.width = caps.minImageExtent.width;
+ }
+ SkASSERT(extent.width <= caps.maxImageExtent.width);
+ // clamp height
+ if (extent.height < caps.minImageExtent.height) {
+ extent.height = caps.minImageExtent.height;
+ }
+ SkASSERT(extent.height <= caps.maxImageExtent.height);
+
+ uint32_t imageCount = caps.minImageCount + 2;
+ if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
+ // Application must settle for fewer images than desired:
+ imageCount = caps.maxImageCount;
+ }
+
+ // Currently Skia requires the images to be color attchments and support all transfer
+ // operations.
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
+ SkASSERT(caps.supportedTransforms & caps.currentTransform);
+ SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
+ VkCompositeAlphaFlagBitsKHR composite_alpha =
+ (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+
+ // Pick our surface format. For now, just make sure it matches our sRGB request:
+ VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
+ VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
+
+ bool wantSRGB = false;
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ wantSRGB = true;
+#endif
+ for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
+ // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB
+ VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
+ if (desiredFormat == surfaceFormats[i].format) {
+ surfaceFormat = surfaceFormats[i].format;
+ colorSpace = surfaceFormats[i].colorSpace;
+ }
+ }
+
+ if (VK_FORMAT_UNDEFINED == surfaceFormat) {
+ return false;
+ }
+
+ // If mailbox mode is available, use it, as it is the lowest-latency non-
+ // tearing mode. If not, fall back to FIFO which is always available.
+ VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
+ for (uint32_t i = 0; i < presentModeCount; ++i) {
+ // use mailbox
+ if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
+ mode = presentModes[i];
+ break;
+ }
+ }
+
+ VkSwapchainCreateInfoKHR swapchainCreateInfo;
+ memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
+ swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swapchainCreateInfo.surface = surface->mVkSurface;
+ swapchainCreateInfo.minImageCount = imageCount;
+ swapchainCreateInfo.imageFormat = surfaceFormat;
+ swapchainCreateInfo.imageColorSpace = colorSpace;
+ swapchainCreateInfo.imageExtent = extent;
+ swapchainCreateInfo.imageArrayLayers = 1;
+ swapchainCreateInfo.imageUsage = usageFlags;
+
+ uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex };
+ if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
+ swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+ swapchainCreateInfo.queueFamilyIndexCount = 2;
+ swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
+ } else {
+ swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchainCreateInfo.queueFamilyIndexCount = 0;
+ swapchainCreateInfo.pQueueFamilyIndices = nullptr;
+ }
+
+ swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ swapchainCreateInfo.compositeAlpha = composite_alpha;
+ swapchainCreateInfo.presentMode = mode;
+ swapchainCreateInfo.clipped = true;
+ swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
+
+ res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
+ &surface->mSwapchain);
+ if (VK_SUCCESS != res) {
+ return false;
+ }
+
+ // destroy the old swapchain
+ if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
+ mDeviceWaitIdle(mBackendContext->fDevice);
+
+ destroyBuffers(surface);
+
+ mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
+ }
+
+ createBuffers(surface, surfaceFormat, extent);
+
+ return true;
+}
+
+
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
+ initialize();
+
+ if (!window) {
+ return nullptr;
+ }
+
+ VulkanSurface* surface = new VulkanSurface();
+
+ VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+ memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+ surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ surfaceCreateInfo.pNext = nullptr;
+ surfaceCreateInfo.flags = 0;
+ surfaceCreateInfo.window = window;
+
+ VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo,
+ nullptr, &surface->mVkSurface);
+ if (VK_SUCCESS != res) {
+ delete surface;
+ return nullptr;
+ }
+
+SkDEBUGCODE(
+ VkBool32 supported;
+ res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice,
+ mPresentQueueIndex, surface->mVkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of presentation with any
+ // native window.
+ SkASSERT(VK_SUCCESS == res && supported);
+);
+
+ if (!createSwapchain(surface)) {
+ destroySurface(surface);
+ return nullptr;
+ }
+
+ return surface;
+}
+
+// Helper to know which src stage flags we need to set when transitioning to the present layout
+static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) {
+ if (VK_IMAGE_LAYOUT_GENERAL == layout) {
+ return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
+ return VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
+ return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+ } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
+ return VK_PIPELINE_STAGE_HOST_BIT;
+ }
+
+ SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
+ return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+}
+
+// Helper to know which src access mask we need to set when transitioning to the present layout
+static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
+ VkAccessFlags flags = 0;
+ if (VK_IMAGE_LAYOUT_GENERAL == layout) {
+ flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_TRANSFER_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT |
+ VK_ACCESS_SHADER_READ_BIT |
+ VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
+ } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
+ flags = VK_ACCESS_HOST_WRITE_BIT;
+ } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
+ flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
+ flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+ } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
+ flags = VK_ACCESS_TRANSFER_WRITE_BIT;
+ } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
+ flags = VK_ACCESS_TRANSFER_READ_BIT;
+ } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
+ flags = VK_ACCESS_SHADER_READ_BIT;
+ }
+ return flags;
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface) {
+ VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
+ surface->mCurrentBackbufferIndex;
+ GrVkImageInfo* imageInfo;
+ SkSurface* skSurface = surface->mSurfaces[backbuffer->mImageIndex].get();
+ skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
+ SkSurface::kFlushRead_BackendHandleAccess);
+ // Check to make sure we never change the actually wrapped image
+ SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
+
+ // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
+ // previous work is complete for before presenting. So we first add the necessary barrier here.
+ VkImageLayout layout = imageInfo->fImageLayout;
+ VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+
+ VkImageMemoryBarrier imageMemoryBarrier = {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
+ mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
+ mPresentQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ };
+
+ mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
+ VkCommandBufferBeginInfo info;
+ memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
+ info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ info.flags = 0;
+ mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0,
+ 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+ mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
+
+ surface->mImageLayouts[backbuffer->mImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ // insert the layout transfer into the queue and wait on the acquire
+ VkSubmitInfo submitInfo;
+ memset(&submitInfo, 0, sizeof(VkSubmitInfo));
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.waitSemaphoreCount = 0;
+ submitInfo.pWaitDstStageMask = 0;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
+ submitInfo.signalSemaphoreCount = 1;
+ // When this command buffer finishes we will signal this semaphore so that we know it is now
+ // safe to present the image to the screen.
+ submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
+
+ // Attach second fence to submission here so we can track when the command buffer finishes.
+ mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
+
+ // Submit present operation to present queue. We use a semaphore here to make sure all rendering
+ // to the image is complete and that the layout has been change to present on the graphics
+ // queue.
+ const VkPresentInfoKHR presentInfo =
+ {
+ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
+ NULL, // pNext
+ 1, // waitSemaphoreCount
+ &backbuffer->mRenderSemaphore, // pWaitSemaphores
+ 1, // swapchainCount
+ &surface->mSwapchain, // pSwapchains
+ &backbuffer->mImageIndex, // pImageIndices
+ NULL // pResults
+ };
+
+ mQueuePresentKHR(mPresentQueue, &presentInfo);
+
+ surface->mBackbuffer.reset();
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
new file mode 100644
index 0000000..f0e3320
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VULKANMANAGER_H
+#define VULKANMANAGER_H
+
+#include <SkSurface.h>
+#include <vk/GrVkBackendContext.h>
+
+#include <vulkan/vulkan.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+class VulkanSurface {
+public:
+ VulkanSurface() {}
+
+ sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
+
+private:
+ friend class VulkanManager;
+ struct BackbufferInfo {
+ uint32_t mImageIndex; // image this is associated with
+ VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
+ VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
+ VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render
+ // We use these fences to make sure the above Command buffers have finished their work
+ // before attempting to reuse them or destroy them.
+ VkFence mUsageFences[2];
+ };
+
+ sk_sp<SkSurface> mBackbuffer;
+
+ VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
+ VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
+
+ BackbufferInfo* mBackbuffers;
+ uint32_t mCurrentBackbufferIndex;
+
+ uint32_t mImageCount;
+ VkImage* mImages;
+ VkImageLayout* mImageLayouts;
+ sk_sp<SkSurface>* mSurfaces;
+};
+
+// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
+// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
+// windowing contexts. The VulkanManager must be initialized before use.
+class VulkanManager {
+public:
+ // Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
+ // be call once before use of the VulkanManager. Multiple calls after the first will simiply
+ // return.
+ void initialize();
+
+ // Quick check to see if the VulkanManager has been initialized.
+ bool hasVkContext() { return mBackendContext.get() != nullptr; }
+
+ // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
+ // VulkanSurface object which is returned.
+ VulkanSurface* createSurface(ANativeWindow* window);
+
+ // Destroy the VulkanSurface and all associated vulkan objects.
+ void destroySurface(VulkanSurface* surface);
+
+ // Cleans up all the global state in the VulkanManger.
+ void destroy();
+
+ // No work is needed to make a VulkanSurface current, and all functions require that a
+ // VulkanSurface is passed into them so we just return true here.
+ bool isCurrent(VulkanSurface* surface) { return true; }
+
+ // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also
+ // will transition the VkImage from a present layout to color attachment so that it can be used
+ // by the client for drawing.
+ SkSurface* getBackbufferSurface(VulkanSurface* surface);
+
+ // Presents the current VkImage.
+ void swapBuffers(VulkanSurface* surface);
+
+private:
+ friend class RenderThread;
+
+ explicit VulkanManager(RenderThread& thread);
+ ~VulkanManager() { destroy(); }
+
+ void destroyBuffers(VulkanSurface* surface);
+
+ bool createSwapchain(VulkanSurface* surface);
+ void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent);
+
+ VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
+
+ // simple wrapper class that exists only to initialize a pointer to NULL
+ template <typename FNPTR_TYPE> class VkPtr {
+ public:
+ VkPtr() : fPtr(NULL) {}
+ VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
+ operator FNPTR_TYPE() const { return fPtr; }
+ private:
+ FNPTR_TYPE fPtr;
+ };
+
+ // WSI interface functions
+ VkPtr<PFN_vkCreateAndroidSurfaceKHR> mCreateAndroidSurfaceKHR;
+ VkPtr<PFN_vkDestroySurfaceKHR> mDestroySurfaceKHR;
+ VkPtr<PFN_vkGetPhysicalDeviceSurfaceSupportKHR> mGetPhysicalDeviceSurfaceSupportKHR;
+ VkPtr<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR> mGetPhysicalDeviceSurfaceCapabilitiesKHR;
+ VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR;
+ VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR;
+
+ VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR;
+ VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR;
+ VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR;
+ VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR;
+ VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
+ VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
+
+ // Additional vulkan functions
+ VkPtr<PFN_vkCreateCommandPool> mCreateCommandPool;
+ VkPtr<PFN_vkDestroyCommandPool> mDestroyCommandPool;
+ VkPtr<PFN_vkAllocateCommandBuffers> mAllocateCommandBuffers;
+ VkPtr<PFN_vkFreeCommandBuffers> mFreeCommandBuffers;
+ VkPtr<PFN_vkResetCommandBuffer> mResetCommandBuffer;
+ VkPtr<PFN_vkBeginCommandBuffer> mBeginCommandBuffer;
+ VkPtr<PFN_vkEndCommandBuffer> mEndCommandBuffer;
+ VkPtr<PFN_vkCmdPipelineBarrier> mCmdPipelineBarrier;
+
+ VkPtr<PFN_vkGetDeviceQueue> mGetDeviceQueue;
+ VkPtr<PFN_vkQueueSubmit> mQueueSubmit;
+ VkPtr<PFN_vkQueueWaitIdle> mQueueWaitIdle;
+ VkPtr<PFN_vkDeviceWaitIdle> mDeviceWaitIdle;
+
+ VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore;
+ VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore;
+ VkPtr<PFN_vkCreateFence> mCreateFence;
+ VkPtr<PFN_vkDestroyFence> mDestroyFence;
+ VkPtr<PFN_vkWaitForFences> mWaitForFences;
+ VkPtr<PFN_vkResetFences> mResetFences;
+
+ RenderThread& mRenderThread;
+
+ sk_sp<const GrVkBackendContext> mBackendContext;
+ uint32_t mPresentQueueIndex;
+ VkQueue mPresentQueue = VK_NULL_HANDLE;
+ VkCommandPool mCommandPool = VK_NULL_HANDLE;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* VULKANMANAGER_H */
+
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
new file mode 100644
index 0000000..9b0b950
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+
+class BitmapShaders;
+
+static bool _BitmapShaders(
+ BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
+ "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
+
+class BitmapShaders : public TestScene {
+public:
+ BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ : TestScene()
+ , mAllocator(allocator) { }
+
+ sp<RenderNode> card;
+ void createContent(int width, int height, Canvas& canvas) override {
+ canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
+ sk_sp<Bitmap> hwuiBitmap = mAllocator(200, 200, kRGBA_8888_SkColorType,
+ [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(Color::White);
+ SkCanvas skCanvas(skBitmap);
+ SkPaint skPaint;
+ skPaint.setColor(Color::Red_500);
+ skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+ skPaint.setColor(Color::Blue_500);
+ skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+ });
+
+ SkBitmap bitmap;
+ SkPaint paint;
+ hwuiBitmap->getSkBitmapForShaders(&bitmap);
+
+ sk_sp<SkShader> repeatShader = SkMakeBitmapShader(bitmap,
+ SkShader::TileMode::kRepeat_TileMode,
+ SkShader::TileMode::kRepeat_TileMode,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
+ paint.setShader(std::move(repeatShader));
+ canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
+
+ sk_sp<SkShader> mirrorShader = SkMakeBitmapShader(bitmap,
+ SkShader::TileMode::kMirror_TileMode,
+ SkShader::TileMode::kMirror_TileMode,
+ nullptr,
+ kNever_SkCopyPixelsMode,
+ nullptr);
+ paint.setShader(std::move(mirrorShader));
+ canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
+ }
+
+ void doFrame(int frameNr) override { }
+
+ BitmapAllocationTestUtils::BitmapAllocator mAllocator;
+};
\ No newline at end of file
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index ebc1dd7..1f56222 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,6 +17,7 @@
#include "tests/common/LeakChecker.h"
#include "tests/common/TestScene.h"
+#include "hwui/Typeface.h"
#include "protos/hwui.pb.h"
#include "Properties.h"
@@ -303,6 +304,8 @@
// set defaults
gOpts.count = 150;
+ Typeface::setRobotoTypefaceForTest();
+
parseOptions(argc, argv);
if (!gBenchmarkReporter && gOpts.renderOffscreen) {
gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index da724a9..bbaf267 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -182,7 +182,7 @@
canvas->insertReorderBarrier(true);
// Draw child loop
- for (int i = 0; i < benchState.range_x(); i++) {
+ for (int i = 0; i < benchState.range(0); i++) {
canvas->drawRenderNode(child.get());
}
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index d68f5bd..398e7a8 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -113,7 +113,7 @@
void BM_FrameBuilder_defer_scene(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
- const char* sceneName = *(SCENES.begin() + state.range_x());
+ const char* sceneName = *(SCENES.begin() + state.range(0));
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
while (state.KeepRunning()) {
@@ -129,7 +129,7 @@
void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
- const char* sceneName = *(SCENES.begin() + state.range_x());
+ const char* sceneName = *(SCENES.begin() + state.range(0));
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp
index 9771c85..b5abf5b 100644
--- a/libs/hwui/tests/microbench/main.cpp
+++ b/libs/hwui/tests/microbench/main.cpp
@@ -17,6 +17,8 @@
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
+#include "hwui/Typeface.h"
+
#include <benchmark/benchmark.h>
#include <memory>
@@ -27,6 +29,7 @@
int main(int argc, char** argv) {
debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>());
benchmark::Initialize(&argc, argv);
+ Typeface::setRobotoTypefaceForTest();
benchmark::RunSpecifiedBenchmarks();
return 0;
}
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index d05bdbf..cea84c0 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -20,6 +20,7 @@
#include "Caches.h"
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
+#include "hwui/Typeface.h"
#include "thread/TaskManager.h"
#include "tests/common/LeakChecker.h"
@@ -50,6 +51,13 @@
raise(sig);
}
+class TypefaceEnvironment : public testing::Environment {
+public:
+ virtual void SetUp() {
+ Typeface::setRobotoTypefaceForTest();
+ }
+};
+
int main(int argc, char* argv[]) {
// Register a crash handler
struct sigaction sa;
@@ -69,6 +77,8 @@
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
+ testing::AddGlobalTestEnvironment(new TypefaceEnvironment());
+
int ret = RUN_ALL_TESTS();
test::LeakChecker::checkForLeaks();
return ret;
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index fe1ee02..fa3d8bd 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -553,7 +553,7 @@
}
};
-IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IMountService")
+IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IStorageManager")
// ----------------------------------------------------------------------
diff --git a/libs/storage/IMountServiceListener.cpp b/libs/storage/IMountServiceListener.cpp
index 6a093fd..033d70d 100644
--- a/libs/storage/IMountServiceListener.cpp
+++ b/libs/storage/IMountServiceListener.cpp
@@ -34,7 +34,7 @@
const String16& /* oldState */, const String16& /* newState */) { }
};
-IMPLEMENT_META_INTERFACE(MountServiceListener, "android.os.storage.IMountServiceListener")
+IMPLEMENT_META_INTERFACE(MountServiceListener, "android.os.storage.IStorageEventListener")
// ----------------------------------------------------------------------
diff --git a/libs/storage/IMountShutdownObserver.cpp b/libs/storage/IMountShutdownObserver.cpp
index 6114d4a..e5de603 100644
--- a/libs/storage/IMountShutdownObserver.cpp
+++ b/libs/storage/IMountShutdownObserver.cpp
@@ -31,7 +31,7 @@
virtual void onShutDownComplete(const int32_t /* statusCode */) {}
};
-IMPLEMENT_META_INTERFACE(MountShutdownObserver, "android.os.storage.IMountShutdownObserver")
+IMPLEMENT_META_INTERFACE(MountShutdownObserver, "android.os.storage.IStorageShutdownObserver")
status_t BnMountShutdownObserver::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
index 8870d2a..e86ad1a 100644
--- a/location/java/android/location/IFusedProvider.aidl
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -22,11 +22,11 @@
* Interface definition for Location providers that require FLP services.
* @hide
*/
-interface IFusedProvider {
+oneway interface IFusedProvider {
/**
* Provides access to a FusedLocationHardware instance needed for the provider to work.
*
* @param instance The FusedLocationHardware available for the provider to use.
*/
void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
-}
\ No newline at end of file
+}
diff --git a/location/java/android/location/IGeofenceProvider.aidl b/location/java/android/location/IGeofenceProvider.aidl
index 5a5fdc6..d4ff0dd 100644
--- a/location/java/android/location/IGeofenceProvider.aidl
+++ b/location/java/android/location/IGeofenceProvider.aidl
@@ -23,6 +23,6 @@
*
* {@hide}
*/
-interface IGeofenceProvider {
+oneway interface IGeofenceProvider {
void setGeofenceHardware(in IGeofenceHardware proxy);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b5e3af0..43fb4b9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1513,9 +1513,9 @@
}
@Override
- void playerSetVolume(float leftVolume, float rightVolume) {
- leftVolume = clampGainOrLevel(leftVolume);
- rightVolume = clampGainOrLevel(rightVolume);
+ void playerSetVolume(boolean muting, float leftVolume, float rightVolume) {
+ leftVolume = clampGainOrLevel(muting ? 0.0f : leftVolume);
+ rightVolume = clampGainOrLevel(muting ? 0.0f : rightVolume);
native_setVolume(leftVolume, rightVolume);
}
@@ -2393,8 +2393,8 @@
}
@Override
- int playerSetAuxEffectSendLevel(float level) {
- level = clampGainOrLevel(level);
+ int playerSetAuxEffectSendLevel(boolean muting, float level) {
+ level = clampGainOrLevel(muting ? 0.0f : level);
int err = native_setAuxEffectSendLevel(level);
return err == 0 ? SUCCESS : ERROR;
}
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 4b1e39f..5f6686a 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -26,14 +26,14 @@
*/
interface IRingtonePlayer {
/** Used for Ringtone.java playback */
- void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
- void stop(IBinder token);
+ oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
+ oneway void stop(IBinder token);
boolean isPlaying(IBinder token);
- void setPlaybackProperties(IBinder token, float volume, boolean looping);
+ oneway void setPlaybackProperties(IBinder token, float volume, boolean looping);
/** Used for Notification sound playback. */
- void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
- void stopAsync();
+ oneway void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
+ oneway void stopAsync();
/** Return the title of the media. */
String getTitle(in Uri uri);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 82cf965..36ad90b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1826,8 +1826,8 @@
}
@Override
- void playerSetVolume(float leftVolume, float rightVolume) {
- _setVolume(leftVolume, rightVolume);
+ void playerSetVolume(boolean muting, float leftVolume, float rightVolume) {
+ _setVolume(muting ? 0.0f : leftVolume, muting ? 0.0f : rightVolume);
}
private native void _setVolume(float leftVolume, float rightVolume);
@@ -1900,8 +1900,8 @@
}
@Override
- int playerSetAuxEffectSendLevel(float level) {
- _setAuxEffectSendLevel(level);
+ int playerSetAuxEffectSendLevel(boolean muting, float level) {
+ _setAuxEffectSendLevel(muting ? 0.0f : level);
return AudioSystem.SUCCESS;
}
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index b262d97..690a553 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -39,6 +39,11 @@
*/
public abstract class PlayerBase {
+ private final static String TAG = "PlayerBase";
+ private static IAudioService sService; //lazy initialization, use getService()
+ /** Debug app ops */
+ protected static final boolean DEBUG_APP_OPS = Log.isLoggable(TAG + ".AO", Log.DEBUG);
+
// parameters of the player that affect AppOps
protected AudioAttributes mAttributes;
protected float mLeftVolume = 1.0f;
@@ -51,7 +56,6 @@
private boolean mHasAppOpsPlayAudio = true;
private final Object mAppOpsLock = new Object();
-
/**
* Constructor. Must be given audio attributes, as they are required for AppOps.
* @param attr non-null audio attributes
@@ -101,7 +105,7 @@
void baseStart() {
synchronized (mAppOpsLock) {
if (isRestricted_sync()) {
- playerSetVolume(0, 0);
+ playerSetVolume(true/*muting*/,0, 0);
}
}
}
@@ -114,7 +118,7 @@
return;
}
}
- playerSetVolume(leftVolume, rightVolume);
+ playerSetVolume(false/*muting*/,leftVolume, rightVolume);
}
int baseSetAuxEffectSendLevel(float level) {
@@ -124,7 +128,7 @@
return AudioSystem.SUCCESS;
}
}
- return playerSetAuxEffectSendLevel(level);
+ return playerSetAuxEffectSendLevel(false/*muting*/, level);
}
/**
@@ -159,11 +163,18 @@
try {
if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
if (mHasAppOpsPlayAudio) {
- playerSetVolume(mLeftVolume, mRightVolume);
- playerSetAuxEffectSendLevel(mAuxEffectSendLevel);
+ if (DEBUG_APP_OPS) {
+ Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume
+ + "/" + mRightVolume);
+ }
+ playerSetVolume(false/*muting*/, mLeftVolume, mRightVolume);
+ playerSetAuxEffectSendLevel(false/*muting*/, mAuxEffectSendLevel);
} else {
- playerSetVolume(0.0f, 0.0f);
- playerSetAuxEffectSendLevel(0.0f);
+ if (DEBUG_APP_OPS) {
+ Log.v(TAG, "updateAppOpsPlayAudio: muting player");
+ }
+ playerSetVolume(true/*muting*/, 0.0f, 0.0f);
+ playerSetAuxEffectSendLevel(true/*muting*/, 0.0f);
}
}
} catch (Exception e) {
@@ -171,7 +182,6 @@
}
}
-
/**
* To be called by the subclass whenever an operation is potentially restricted.
* As the media player-common behavior are incorporated into this class, the subclass's need
@@ -189,10 +199,41 @@
if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
return false;
}
+ // check force audibility flag and camera restriction
+ if (((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0)
+ && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)) {
+ boolean cameraSoundForced = false;
+ try {
+ cameraSoundForced = getService().isCameraSoundForced();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot access AudioService in isRestricted_sync()");
+ } catch (NullPointerException e) {
+ Log.e(TAG, "Null AudioService in isRestricted_sync()");
+ }
+ if (cameraSoundForced) {
+ return false;
+ }
+ }
return true;
}
+ private static IAudioService getService()
+ {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ return sService;
+ }
+
// Abstract methods a subclass needs to implement
- abstract void playerSetVolume(float leftVolume, float rightVolume);
- abstract int playerSetAuxEffectSendLevel(float level);
+ /**
+ * Abstract method for the subclass behavior's for volume and muting commands
+ * @param muting if true, the player is to be muted, and the volume values can be ignored
+ * @param leftVolume the left volume to use if muting is false
+ * @param rightVolume the right volume to use if muting is false
+ */
+ abstract void playerSetVolume(boolean muting, float leftVolume, float rightVolume);
+ abstract int playerSetAuxEffectSendLevel(boolean muting, float level);
}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 9fafda4..b429e22 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -35,9 +35,6 @@
import android.util.AndroidRuntimeException;
import android.util.Log;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
-
/**
* The SoundPool class manages and plays audio resources for applications.
@@ -111,7 +108,7 @@
* another level, a new SoundPool is created, sounds are loaded, and play
* resumes.</p>
*/
-public class SoundPool {
+public class SoundPool extends PlayerBase {
static { System.loadLibrary("soundpool"); }
// SoundPool messages
@@ -130,10 +127,6 @@
private final Object mLock;
private final AudioAttributes mAttributes;
- private final IAppOpsService mAppOps;
- private final IAppOpsCallback mAppOpsCallback;
-
- private static IAudioService sService;
/**
* Constructor. Constructs a SoundPool object with the following
@@ -156,32 +149,14 @@
}
private SoundPool(int maxStreams, AudioAttributes attributes) {
+ super(attributes);
+
// do native setup
if (native_setup(new WeakReference<SoundPool>(this), maxStreams, attributes) != 0) {
throw new RuntimeException("Native setup failed");
}
mLock = new Object();
mAttributes = attributes;
- IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
- mAppOps = IAppOpsService.Stub.asInterface(b);
- // initialize mHasAppOpsPlayAudio
- updateAppOpsPlayAudio();
- // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
- mAppOpsCallback = new IAppOpsCallback.Stub() {
- public void opChanged(int op, int uid, String packageName) {
- synchronized (mLock) {
- if (op == AppOpsManager.OP_PLAY_AUDIO) {
- updateAppOpsPlayAudio();
- }
- }
- }
- };
- try {
- mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
- ActivityThread.currentPackageName(), mAppOpsCallback);
- } catch (RemoteException e) {
- mHasAppOpsPlayAudio = false;
- }
}
/**
@@ -192,11 +167,7 @@
* should be set to null.
*/
public final void release() {
- try {
- mAppOps.stopWatchingMode(mAppOpsCallback);
- } catch (RemoteException e) {
- // nothing to do here, the SoundPool is being released anyway
- }
+ baseRelease();
native_release();
}
@@ -333,9 +304,7 @@
*/
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
- if (isRestricted()) {
- leftVolume = rightVolume = 0;
- }
+ baseStart();
return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
}
@@ -408,12 +377,26 @@
* @param rightVolume right volume value (range = 0.0 to 1.0)
*/
public final void setVolume(int streamID, float leftVolume, float rightVolume) {
- if (isRestricted()) {
- return;
- }
+ // unlike other subclasses of PlayerBase, we are not calling
+ // baseSetVolume(leftVolume, rightVolume) as we need to keep track of each
+ // volume separately for each player, so we still send the command, but
+ // handle mute/unmute separately through playerSetVolume()
_setVolume(streamID, leftVolume, rightVolume);
}
+
+ @Override
+ void playerSetVolume(boolean muting, float leftVolume, float rightVolume) {
+ // not used here to control the player volume directly, but used to mute/unmute
+ _mute(muting);
+ }
+
+ @Override
+ int playerSetAuxEffectSendLevel(boolean muting, float level) {
+ // no aux send functionality so no-op
+ return AudioSystem.SUCCESS;
+ }
+
/**
* Similar, except set volume of all channels to same value.
* @hide
@@ -494,55 +477,6 @@
}
}
- private static IAudioService getService()
- {
- if (sService != null) {
- return sService;
- }
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- sService = IAudioService.Stub.asInterface(b);
- return sService;
- }
-
- private boolean isRestricted() {
- // check app ops
- if (mHasAppOpsPlayAudio) {
- return false;
- }
- // check bypass flag
- if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
- return false;
- }
- // check force audibility flag and camera restriction
- if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_AUDIBILITY_ENFORCED) != 0) {
-// FIXME: should also check usage when set properly by camera app
-// && (mAttributes.getUsage() == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- boolean cameraSoundForced = false;
- try {
- cameraSoundForced = getService().isCameraSoundForced();
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot access AudioService in isRestricted()");
- } catch (NullPointerException e) {
- Log.e(TAG, "Null AudioService in isRestricted()");
- }
- if (cameraSoundForced) {
- return false;
- }
- }
- return true;
- }
-
- private void updateAppOpsPlayAudio() {
- try {
- final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
- mAttributes.getUsage(),
- Process.myUid(), ActivityThread.currentPackageName());
- mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED);
- } catch (RemoteException e) {
- mHasAppOpsPlayAudio = false;
- }
- }
-
private native final int _load(FileDescriptor fd, long offset, long length, int priority);
private native final int native_setup(Object weakRef, int maxStreams,
@@ -553,6 +487,8 @@
private native final void _setVolume(int streamID, float leftVolume, float rightVolume);
+ private native final void _mute(boolean muting);
+
// post event from native code to message handler
@SuppressWarnings("unchecked")
private static void postEventFromNative(Object ref, int msg, int arg1, int arg2, Object obj) {
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index d2dc440..87092d0 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -60,6 +60,7 @@
ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
mQuit = false;
+ mMuted = false;
mDecodeThread = 0;
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
mAllocated = 0;
@@ -366,6 +367,19 @@
}
}
+void SoundPool::mute(bool muting)
+{
+ ALOGV("mute(%d)", muting);
+ Mutex::Autolock lock(&mLock);
+ mMuted = muting;
+ if (!mChannels.empty()) {
+ for (List<SoundChannel*>::iterator iter = mChannels.begin();
+ iter != mChannels.end(); ++iter) {
+ (*iter)->mute(muting);
+ }
+ }
+}
+
void SoundPool::autoResume()
{
ALOGV("autoResume()");
@@ -1032,7 +1046,7 @@
{
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- if (mAudioTrack != NULL)
+ if (mAudioTrack != NULL && !mMuted)
mAudioTrack->setVolume(leftVolume, rightVolume);
}
@@ -1042,6 +1056,19 @@
setVolume_l(leftVolume, rightVolume);
}
+void SoundChannel::mute(bool muting)
+{
+ Mutex::Autolock lock(&mLock);
+ mMuted = muting;
+ if (mAudioTrack != NULL) {
+ if (mMuted) {
+ mAudioTrack->setVolume(0.0f, 0.0f);
+ } else {
+ mAudioTrack->setVolume(mLeftVolume, mRightVolume);
+ }
+ }
+}
+
void SoundChannel::setLoop(int loop)
{
Mutex::Autolock lock(&mLock);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index aff101f..5c48a90 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -114,13 +114,14 @@
public:
enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
SoundChannel() : mState(IDLE), mNumChannels(1),
- mPos(0), mToggle(0), mAutoPaused(false) {}
+ mPos(0), mToggle(0), mAutoPaused(false), mMuted(false) {}
~SoundChannel();
void init(SoundPool* soundPool);
void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
int priority, int loop, float rate);
void setVolume_l(float leftVolume, float rightVolume);
void setVolume(float leftVolume, float rightVolume);
+ void mute(bool muting);
void stop_l();
void stop();
void pause();
@@ -154,6 +155,7 @@
unsigned long mToggle;
bool mAutoPaused;
int mPrevSampleID;
+ bool mMuted;
};
// application object for managing a pool of sounds
@@ -168,6 +170,7 @@
int play(int sampleID, float leftVolume, float rightVolume, int priority,
int loop, float rate);
void pause(int channelID);
+ void mute(bool muting);
void autoPause();
void resume(int channelID);
void autoResume();
@@ -222,6 +225,7 @@
int mNextSampleID;
int mNextChannelID;
bool mQuit;
+ bool mMuted;
// callback
Mutex mCallbackLock;
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index ab3e340..9d0c1f8 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -132,6 +132,15 @@
}
static void
+android_media_SoundPool_mute(JNIEnv *env, jobject thiz, jboolean muting)
+{
+ ALOGV("android_media_SoundPool_mute(%d)", muting);
+ SoundPool *ap = MusterSoundPool(env, thiz);
+ if (ap == NULL) return;
+ ap->mute(muting == JNI_TRUE);
+}
+
+static void
android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID,
jint priority)
{
@@ -270,6 +279,10 @@
"(IFF)V",
(void *)android_media_SoundPool_setVolume
},
+ { "_mute",
+ "(Z)V",
+ (void *)android_media_SoundPool_mute
+ },
{ "setPriority",
"(II)V",
(void *)android_media_SoundPool_setPriority
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index bfc9ff3..7fa5736 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -27,7 +27,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.text.Editable;
import android.text.TextWatcher;
@@ -64,7 +64,7 @@
Handler mHandler;
IBackupManager mBackupManager;
- IMountService mMountService;
+ IStorageManager mStorageManager;
FullObserver mObserver;
int mToken;
boolean mIsEncrypted;
@@ -158,7 +158,7 @@
}
mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
mHandler = new ObserverHandler(getApplicationContext());
final Object oldObserver = getLastNonConfigurationInstance();
@@ -271,14 +271,14 @@
boolean deviceIsEncrypted() {
try {
- return mMountService.getEncryptionState()
+ return mStorageManager.getEncryptionState()
!= StorageManager.ENCRYPTION_STATE_NONE
- && mMountService.getPasswordType()
+ && mStorageManager.getPasswordType()
!= StorageManager.CRYPT_TYPE_DEFAULT;
} catch (Exception e) {
- // If we can't talk to the mount service we have a serious problem; fail
+ // If we can't talk to the storagemanager service we have a serious problem; fail
// "secure" i.e. assuming that the device is encrypted.
- Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
+ Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
return true;
}
}
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index c2ca998..f442219 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -26,16 +26,6 @@
android:directBootAware="true">
<library android:name="android.ext.services"/>
-
- <service android:name=".notification.Ranker"
- android:label="@string/notification_ranker"
- android:permission="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
- android:exported="true">
- <intent-filter>
- <action android:name="android.service.notification.NotificationRankerService" />
- </intent-filter>
- </service>
-
</application>
</manifest>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index b77ff10..531e517 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -16,6 +16,4 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Android Services Library</string>
- <string name="notification_ranker">Android Notification Ranking Service</string>
- <string name="notification_ranker_autobundle_explanation">Auto-grouping updated by Ranking Service</string>
</resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
deleted file mode 100644
index 2feb51f..0000000
--- a/packages/ExtServices/src/android/ext/services/notification/Ranker.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.ext.services.notification;
-
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.notification.Adjustment;
-import android.service.notification.NotificationRankerService;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-
-import android.ext.services.R;
-
-/**
- * Class that provides an updatable ranker module for the notification manager.
- * TODO: delete
- */
-public final class Ranker extends NotificationRankerService {
- private static final String TAG = "RocketRanker";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- @Override
- public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
- boolean user) {
- return null;
- }
-}
\ No newline at end of file
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 9af20d0..8cf375a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -20,6 +20,8 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.UriPermission;
+import android.content.pm.ParceledListSlice;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
@@ -63,6 +65,7 @@
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
public class ExternalStorageProvider extends DocumentsProvider {
private static final String TAG = "ExternalStorage";
@@ -502,6 +505,70 @@
return getDocIdForFile(file);
}
+ private Uri getDocumentUri(String path, List<UriPermission> accessUriPermissions)
+ throws FileNotFoundException {
+ File doc = new File(path);
+
+ final String docId = getDocIdForFile(doc);
+
+ UriPermission docUriPermission = null;
+ UriPermission treeUriPermission = null;
+ for (UriPermission uriPermission : accessUriPermissions) {
+ final Uri uri = uriPermission.getUri();
+ if (AUTHORITY.equals(uri.getAuthority())) {
+ boolean matchesRequestedDoc = false;
+ if (DocumentsContract.isTreeUri(uri)) {
+ final String parentDocId = DocumentsContract.getTreeDocumentId(uri);
+ File parentFile = getFileForDocId(parentDocId);
+ if (FileUtils.contains(parentFile, doc)) {
+ treeUriPermission = uriPermission;
+ matchesRequestedDoc = true;
+ }
+ } else {
+ final String candidateDocId = DocumentsContract.getDocumentId(uri);
+ final File candidateDoc = getFileForDocId(candidateDocId);
+ if (Objects.equals(doc.getAbsolutePath(), candidateDoc.getAbsolutePath())) {
+ docUriPermission = uriPermission;
+ matchesRequestedDoc = true;
+ }
+ }
+
+ if (matchesRequestedDoc && allowsBothReadAndWrite(uriPermission)) {
+ // This URI permission provides everything an app can get, no need to
+ // further check any other granted URI.
+ break;
+ }
+ }
+ }
+
+ // Full permission URI first.
+ if (allowsBothReadAndWrite(treeUriPermission)) {
+ return DocumentsContract.buildDocumentUriUsingTree(treeUriPermission.getUri(), docId);
+ }
+
+ if (allowsBothReadAndWrite(docUriPermission)) {
+ return docUriPermission.getUri();
+ }
+
+ // Then partial permission URI.
+ if (treeUriPermission != null) {
+ return DocumentsContract.buildDocumentUriUsingTree(treeUriPermission.getUri(), docId);
+ }
+
+ if (docUriPermission != null) {
+ return docUriPermission.getUri();
+ }
+
+ throw new SecurityException("The app is not given any access to the document under path " +
+ path + " with permissions granted in " + accessUriPermissions);
+ }
+
+ private static boolean allowsBothReadAndWrite(UriPermission permission) {
+ return permission != null
+ && permission.isReadPermission()
+ && permission.isWritePermission();
+ }
+
@Override
public String renameDocument(String docId, String displayName) throws FileNotFoundException {
// Since this provider treats renames as generating a completely new
@@ -721,6 +788,21 @@
}
break;
}
+ case "getDocumentId": {
+ final String path = arg;
+ final List<UriPermission> accessUriPermissions =
+ extras.getParcelableArrayList(AUTHORITY + ".extra.uriPermissions");
+
+ try {
+ final Bundle out = new Bundle();
+ final Uri uri = getDocumentUri(path, accessUriPermissions);
+ out.putParcelable(DocumentsContract.EXTRA_URI, uri);
+ return out;
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException("File in " + path + " is not found.", e);
+ }
+
+ }
default:
Log.w(TAG, "unknown method passed to call(): " + method);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 0474df7..e3ab05d 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -16,7 +16,7 @@
package com.android.keyguard;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -34,7 +34,7 @@
import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.policy.EmergencyAffordanceManager;
@@ -171,7 +171,7 @@
// should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
try {
- ActivityManagerNative.getDefault().stopSystemLockTaskMode();
+ ActivityManager.getService().stopSystemLockTaskMode();
} catch (RemoteException e) {
Slog.w(LOG_TAG, "Failed to stop app pinning");
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 66e56e0..6a2949a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -28,7 +28,6 @@
import static android.os.BatteryManager.EXTRA_STATUS;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.UserSwitchObserver;
@@ -459,7 +458,7 @@
try {
final int userId;
try {
- userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ userId = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
Log.e(TAG, "Failed to get current user id: ", e);
return;
@@ -1088,7 +1087,7 @@
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ ActivityManager.getService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
diff --git a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java
index 43cc1d6..d95af61 100644
--- a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java
+++ b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java
@@ -530,7 +530,8 @@
private int addSP(String xml) throws IOException, SAXException {
WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- return wifiManager.addPasspointManagementObject(xml);
+ // TODO(b/32883320): use the new API for adding Passpoint configuration.
+ return 0;
}
private int modifySP(HomeSP homeSP, Collection<MOData> mods) throws IOException {
@@ -540,7 +541,8 @@
defMods.add(new PasspointManagementObjectDefinition(mod.getBaseURI(),
mod.getURN(), mod.getMOTree().toXml()));
}
- return wifiManager.modifyPasspointManagementObject(homeSP.getFQDN(), defMods);
+ // TODO(b/32883320): use the new API to update Passpoint configuration.
+ return 0;
}
private void reconnect(Network osuNetwork, int newNwkId) {
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index a50391f..2450be3 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -32,7 +32,7 @@
<string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="pages_range_example" msgid="8558694453556945172">"npr. 1—5,8,11—13"</string>
<string name="print_preview" msgid="8010217796057763343">"Pregled prije štampanja"</string>
- <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF preglednik za prikaz"</string>
+ <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF pregledavač za prikaz"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je prestala raditi"</string>
<string name="generating_print_job" msgid="3119608742651698916">"Kreiranje zadatka za štampu"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index 1bebebc..7b0a291 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -48,7 +48,7 @@
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.printspooler.R;
import java.text.Collator;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 23c6615..4b51917 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -88,7 +88,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.printspooler.R;
import com.android.printspooler.model.MutexFileProvider;
import com.android.printspooler.model.PrintSpoolerProvider;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 74582f3..6f0caa2 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -63,7 +63,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.printspooler.R;
import java.util.ArrayList;
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 5dcad7a..3b84313 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -168,7 +168,7 @@
<string name="wifi_verbose_logging" msgid="4203729756047242344">"Uitgebreide wifi-logregistratie insch."</string>
<string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agressieve handover van wifi naar mobiel"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string>
- <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele gegevens altijd actief"</string>
+ <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele data altijd actief"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index ac9de74..ea03fb6 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -339,6 +339,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見反映"</string>
+ <string name="help_feedback_label" msgid="6815040660801785649">"說明和意見反映"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 381f903..c3acf0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -35,7 +35,7 @@
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.net.URISyntaxException;
import java.util.Locale;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
index ed411be..14a0e82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -25,12 +26,15 @@
import com.android.settingslib.applications.InterestingConfigChanges;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import static java.lang.String.CASE_INSENSITIVE_ORDER;
+
public class CategoryManager {
private static final String TAG = "CategoryManager";
@@ -111,6 +115,7 @@
mCategoryByKeyMap.put(category.key, category);
}
backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+ normalizePriority(context, mCategoryByKeyMap);
}
}
@@ -163,4 +168,57 @@
}
}
}
+
+ /**
+ * Normalize priority values on tiles across injected from all apps to make sure they don't set
+ * the same priority value. However internal tiles' priority remains unchanged.
+ * <p/>
+ * A list of tiles are considered normalized when their priority value increases in a linear
+ * scan.
+ */
+ @VisibleForTesting
+ synchronized void normalizePriority(Context context,
+ Map<String, DashboardCategory> categoryByKeyMap) {
+ for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
+ normalizePriorityForExternalTiles(context, categoryEntry.getValue());
+ }
+ }
+
+ /**
+ * Normalize priority value for tiles within a single {@code DashboardCategory}.
+ *
+ * @see #normalizePriority(Context, Map)
+ */
+ private synchronized void normalizePriorityForExternalTiles(Context context,
+ DashboardCategory dashboardCategory) {
+ final String skipPackageName = context.getPackageName();
+
+ // Sort tiles based on [package, priority within package]
+ Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> {
+ final String package1 = tile1.intent.getComponent().getPackageName();
+ final String package2 = tile2.intent.getComponent().getPackageName();
+ final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2);
+ // First sort by package name
+ if (packageCompare != 0) {
+ return packageCompare;
+ } else if (TextUtils.equals(package1, skipPackageName)) {
+ return 0;
+ }
+ // Then sort by priority
+ return tile1.priority - tile2.priority;
+ });
+ // Update priority for all items so no package define the same priority value.
+ final int count = dashboardCategory.tiles.size();
+ for (int i = 0; i < count; i++) {
+ final String packageName =
+ dashboardCategory.tiles.get(i).intent.getComponent().getPackageName();
+ if (TextUtils.equals(packageName, skipPackageName)) {
+ // We skip this tile because it's a intent pointing to our own app. We trust the
+ // priority is set correctly, so don't normalize.
+ continue;
+ }
+ dashboardCategory.tiles.get(i).priority = i;
+
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
index 380f622..50bb216 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
@@ -16,7 +16,9 @@
package com.android.settingslib.drawer;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.util.Pair;
import com.android.settingslib.TestConfig;
@@ -116,4 +118,114 @@
// Old category still exists.
assertThat(mCategoryByKeyMap.get(oldCategory).tiles.size()).isEqualTo(1);
}
+
+ @Test
+ public void normalizePriority_singlePackage_shouldReorderBasedOnPriority() {
+ // Create some fake tiles that are not sorted.
+ final String testPackage = "com.android.test";
+ final DashboardCategory category = new DashboardCategory();
+ final Tile tile1 = new Tile();
+ tile1.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class1"));
+ tile1.priority = 100;
+ final Tile tile2 = new Tile();
+ tile2.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class2"));
+ tile2.priority = 50;
+ final Tile tile3 = new Tile();
+ tile3.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class3"));
+ tile3.priority = 200;
+ category.tiles.add(tile1);
+ category.tiles.add(tile2);
+ category.tiles.add(tile3);
+ mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+ // Normalize their priorities
+ mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
+ mCategoryByKeyMap);
+
+ // Verify they are now sorted.
+ assertThat(category.tiles.get(0)).isSameAs(tile2);
+ assertThat(category.tiles.get(1)).isSameAs(tile1);
+ assertThat(category.tiles.get(2)).isSameAs(tile3);
+ // Verify their priority is normalized
+ assertThat(category.tiles.get(0).priority).isEqualTo(0);
+ assertThat(category.tiles.get(1).priority).isEqualTo(1);
+ assertThat(category.tiles.get(2).priority).isEqualTo(2);
+ }
+
+ @Test
+ public void normalizePriority_multiPackage_shouldReorderBasedOnPackageAndPriority() {
+ // Create some fake tiles that are not sorted.
+ final String testPackage1 = "com.android.test1";
+ final String testPackage2 = "com.android.test2";
+ final DashboardCategory category = new DashboardCategory();
+ final Tile tile1 = new Tile();
+ tile1.intent =
+ new Intent().setComponent(new ComponentName(testPackage2, "class1"));
+ tile1.priority = 100;
+ final Tile tile2 = new Tile();
+ tile2.intent =
+ new Intent().setComponent(new ComponentName(testPackage1, "class2"));
+ tile2.priority = 100;
+ final Tile tile3 = new Tile();
+ tile3.intent =
+ new Intent().setComponent(new ComponentName(testPackage1, "class3"));
+ tile3.priority = 50;
+ category.tiles.add(tile1);
+ category.tiles.add(tile2);
+ category.tiles.add(tile3);
+ mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+ // Normalize their priorities
+ mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
+ mCategoryByKeyMap);
+
+ // Verify they are now sorted.
+ assertThat(category.tiles.get(0)).isSameAs(tile3);
+ assertThat(category.tiles.get(1)).isSameAs(tile2);
+ assertThat(category.tiles.get(2)).isSameAs(tile1);
+ // Verify their priority is normalized
+ assertThat(category.tiles.get(0).priority).isEqualTo(0);
+ assertThat(category.tiles.get(1).priority).isEqualTo(1);
+ assertThat(category.tiles.get(2).priority).isEqualTo(2);
+ }
+
+ @Test
+ public void normalizePriority_internalPackageTiles_shouldSkipTileForInternalPackage() {
+ // Create some fake tiles that are not sorted.
+ final String testPackage =
+ ShadowApplication.getInstance().getApplicationContext().getPackageName();
+ final DashboardCategory category = new DashboardCategory();
+ final Tile tile1 = new Tile();
+ tile1.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class1"));
+ tile1.priority = 100;
+ final Tile tile2 = new Tile();
+ tile2.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class2"));
+ tile2.priority = 100;
+ final Tile tile3 = new Tile();
+ tile3.intent =
+ new Intent().setComponent(new ComponentName(testPackage, "class3"));
+ tile3.priority = 50;
+ category.tiles.add(tile1);
+ category.tiles.add(tile2);
+ category.tiles.add(tile3);
+ mCategoryByKeyMap.put(CategoryKey.CATEGORY_HOMEPAGE, category);
+
+ // Normalize their priorities
+ mCategoryManager.normalizePriority(ShadowApplication.getInstance().getApplicationContext(),
+ mCategoryByKeyMap);
+
+ // Verify the sorting order is not changed
+ assertThat(category.tiles.get(0)).isSameAs(tile1);
+ assertThat(category.tiles.get(1)).isSameAs(tile2);
+ assertThat(category.tiles.get(2)).isSameAs(tile3);
+ // Verify their priorities are not changed.
+ assertThat(category.tiles.get(0).priority).isEqualTo(100);
+ assertThat(category.tiles.get(1).priority).isEqualTo(100);
+ assertThat(category.tiles.get(2).priority).isEqualTo(50);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index dd543a3..d784a3a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -645,7 +645,7 @@
if (upgradeVersion == 45) {
/*
- * New settings for MountService
+ * New settings for StorageManagerService
*/
db.beginTransaction();
try {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index bf48e5d..1c51773 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -16,7 +16,7 @@
package com.android.providers.settings;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.backup.IBackupManager;
import android.content.ContentResolver;
@@ -343,7 +343,7 @@
if (loc == null) return; // Couldn't find the saved locale in this version of the software
try {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
Configuration config = am.getConfiguration();
config.locale = loc;
// indicate this isn't some passing default - the user wants this remembered
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 169b01f..461573f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -16,7 +16,7 @@
package com.android.providers.settings;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.IContentProvider;
import android.content.pm.PackageManager;
import android.database.Cursor;
@@ -190,7 +190,7 @@
if (mUser == UserHandle.USER_CURRENT) {
try {
- mUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+ mUser = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
}
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 2170cc1..935d09b 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,6 +5,13 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += \
+ ../../../native/cmds/dumpstate/binder/android/os/IDumpstate.aidl \
+ ../../../native/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl \
+ ../../../native/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+
+LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder
+
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_PACKAGE_NAME := Shell
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e9..d4c7c7a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -112,6 +112,7 @@
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+ <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
<!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
<!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 772c344..47abd4f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -31,6 +31,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.text.NumberFormat;
import java.util.ArrayList;
@@ -44,7 +45,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.FastPrintWriter;
import com.google.android.collect.Lists;
@@ -69,10 +71,16 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.support.v4.content.FileProvider;
@@ -146,10 +154,9 @@
static final String EXTRA_INFO = "android.intent.extra.INFO";
private static final int MSG_SERVICE_COMMAND = 1;
- private static final int MSG_POLL = 2;
- private static final int MSG_DELAYED_SCREENSHOT = 3;
- private static final int MSG_SCREENSHOT_REQUEST = 4;
- private static final int MSG_SCREENSHOT_RESPONSE = 5;
+ private static final int MSG_DELAYED_SCREENSHOT = 2;
+ private static final int MSG_SCREENSHOT_REQUEST = 3;
+ private static final int MSG_SCREENSHOT_RESPONSE = 4;
// Passed to Message.obtain() when msg.arg2 is not used.
private static final int UNUSED_ARG2 = -2;
@@ -165,16 +172,9 @@
*/
static final int SCREENSHOT_DELAY_SECONDS = 3;
- /** Polling frequency, in milliseconds. */
- static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS;
-
- /** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
- private static final long INACTIVITY_TIMEOUT = 10 * DateUtils.MINUTE_IN_MILLIS;
-
- /** System properties used for monitoring progress. */
+ // TODO: will be gone once fully migrated to Binder
+ /** System properties used to communicate with dumpstate progress. */
private static final String DUMPSTATE_PREFIX = "dumpstate.";
- private static final String PROGRESS_SUFFIX = ".progress";
- private static final String MAX_SUFFIX = ".max";
private static final String NAME_SUFFIX = ".name";
/** System property (and value) used to stop dumpstate. */
@@ -190,7 +190,7 @@
private static final String SCREENSHOT_DIR = "bugreports";
/** Managed dumpstate processes (keyed by id) */
- private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
+ private final SparseArray<DumpstateListener> mProcesses = new SparseArray<>();
private Context mContext;
private ServiceHandler mMainHandler;
@@ -267,14 +267,16 @@
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final int size = mProcesses.size();
if (size == 0) {
- writer.printf("No monitored processes");
+ writer.println("No monitored processes");
return;
}
- writer.printf("Foreground id: %d\n\n", mForegroundId);
- writer.printf("Monitored dumpstate processes\n");
- writer.printf("-----------------------------\n");
+ writer.print("Foreground id: "); writer.println(mForegroundId);
+ writer.println("\n");
+ writer.println("Monitored dumpstate processes");
+ writer.println("-----------------------------");
for (int i = 0; i < size; i++) {
- writer.printf("%s\n", mProcesses.valueAt(i));
+ writer.print("#"); writer.println(i + 1);
+ writer.println(mProcesses.valueAt(i).info);
}
}
@@ -288,11 +290,6 @@
@Override
public void handleMessage(Message msg) {
- if (msg.what == MSG_POLL) {
- poll();
- return;
- }
-
if (msg.what == MSG_DELAYED_SCREENSHOT) {
takeScreenshot(msg.arg1, msg.arg2);
return;
@@ -339,7 +336,6 @@
stopSelfWhenDone();
return;
}
- poll();
break;
case INTENT_BUGREPORT_FINISHED:
if (id == 0) {
@@ -367,15 +363,6 @@
return;
}
-
- private void poll() {
- if (pollProgress()) {
- // Keep polling...
- sendEmptyMessageDelayed(MSG_POLL, POLLING_FREQUENCY);
- } else {
- Log.i(TAG, "Stopped polling");
- }
- }
}
/**
@@ -397,11 +384,12 @@
}
private BugreportInfo getInfo(int id) {
- final BugreportInfo info = mProcesses.get(id);
- if (info == null) {
+ final DumpstateListener listener = mProcesses.get(id);
+ if (listener == null) {
Log.w(TAG, "Not monitoring process with ID " + id);
+ return null;
}
- return info;
+ return listener.info;
}
/**
@@ -433,9 +421,15 @@
Log.w(TAG, "ID " + id + " already watched");
return true;
}
- mProcesses.put(info.id, info);
- updateProgress(info);
- return true;
+ final DumpstateListener listener = new DumpstateListener(info);
+ mProcesses.put(info.id, listener);
+ if (listener.connect()) {
+ updateProgress(info);
+ return true;
+ } else {
+ Log.w(TAG, "not updating progress because it could not connect to dumpstate");
+ return false;
+ }
}
/**
@@ -504,10 +498,7 @@
.setActions(infoAction, screenshotAction, cancelAction);
}
- if (DEBUG) {
- Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
- + "): " + percentageText);
- }
+ Log.d(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentageText);
sendForegroundabledNotification(info.id, builder.build());
}
@@ -567,96 +558,11 @@
}
/**
- * Poll {@link SystemProperties} to get the progress on each monitored process.
- *
- * @return whether it should keep polling.
- */
- private boolean pollProgress() {
- final int total = mProcesses.size();
- if (total == 0) {
- Log.d(TAG, "No process to poll progress.");
- }
- int activeProcesses = 0;
- for (int i = 0; i < total; i++) {
- final BugreportInfo info = mProcesses.valueAt(i);
- if (info == null) {
- Log.wtf(TAG, "pollProgress(): null info at index " + i + "(ID = "
- + mProcesses.keyAt(i) + ")");
- continue;
- }
-
- final int pid = info.pid;
- final int id = info.id;
- if (info.finished) {
- if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")");
- continue;
- }
- activeProcesses++;
- final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
- info.realProgress = SystemProperties.getInt(progressKey, 0);
- if (info.realProgress == 0) {
- Log.v(TAG, "System property " + progressKey + " is not set yet");
- }
- final String maxKey = DUMPSTATE_PREFIX + pid + MAX_SUFFIX;
- info.realMax = SystemProperties.getInt(maxKey, info.max);
- if (info.realMax <= 0 ) {
- Log.w(TAG, "Property " + maxKey + " is not positive: " + info.max);
- continue;
- }
- /*
- * Checks whether the progress changed in a way that should be displayed to the user:
- * - info.progress / info.max represents the displayed progress
- * - info.realProgress / info.realMax represents the real progress
- * - since the real progress can decrease, the displayed progress is only updated if it
- * increases
- * - the displayed progress is capped at a maximum (like 99%)
- */
- final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
- int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
- int max = info.realMax;
- int progress = info.realProgress;
-
- if (newPercentage > CAPPED_PROGRESS) {
- progress = newPercentage = CAPPED_PROGRESS;
- max = CAPPED_MAX;
- }
-
- if (newPercentage > oldPercentage) {
- if (DEBUG) {
- if (progress != info.progress) {
- Log.v(TAG, "Updating progress for PID " + pid + "(id: " + id + ") from "
- + info.progress + " to " + progress);
- }
- if (max != info.max) {
- Log.v(TAG, "Updating max progress for PID " + pid + "(id: " + id + ") from "
- + info.max + " to " + max);
- }
- }
- info.progress = progress;
- info.max = max;
- info.lastUpdate = System.currentTimeMillis();
- updateProgress(info);
- } else {
- long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
- if (inactiveTime >= INACTIVITY_TIMEOUT) {
- Log.w(TAG, "No progress update for PID " + pid + " since "
- + info.getFormattedLastUpdate());
- stopProgress(info.id);
- }
- }
- }
- if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
- return activeProcesses > 0;
- }
-
- /**
* Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
* change its values.
*/
private void launchBugreportInfoDialog(int id) {
MetricsLogger.action(this, MetricsEvent.ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS);
- // Copy values so it doesn't lock mProcesses while UI is being updated
- final String name, title, description;
final BugreportInfo info = getInfo(id);
if (info == null) {
// Most likely am killed Shell before user tapped the notification. Since system might
@@ -737,7 +643,7 @@
synchronized (BugreportProgressService.this) {
mTakingScreenshot = flag;
for (int i = 0; i < mProcesses.size(); i++) {
- final BugreportInfo info = mProcesses.valueAt(i);
+ final BugreportInfo info = mProcesses.valueAt(i).info;
if (info.finished) {
Log.d(TAG, "Not updating progress for " + info.id + " while taking screenshot"
+ " because share notification was already sent");
@@ -809,7 +715,7 @@
final int total = mProcesses.size();
if (total > 0) {
for (int i = 0; i < total; i++) {
- final BugreportInfo info = mProcesses.valueAt(i);
+ final BugreportInfo info = mProcesses.valueAt(i).info;
if (!info.finished) {
updateProgress(info);
break;
@@ -848,13 +754,13 @@
Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
return;
}
- mInfoDialog.onBugreportFinished(id);
+ mInfoDialog.onBugreportFinished();
BugreportInfo info = getInfo(id);
if (info == null) {
// Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
Log.v(TAG, "Creating info for untracked ID " + id);
info = new BugreportInfo(mContext, id);
- mProcesses.put(id, info);
+ mProcesses.put(id, new DumpstateListener(info));
}
info.renameScreenshots(mScreenshotsDir);
info.bugreportFile = bugreportFile;
@@ -1363,7 +1269,6 @@
if (bitmap == null) {
return false;
}
- boolean status;
try (final FileOutputStream fos = new FileOutputStream(path)) {
if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
@@ -1570,7 +1475,7 @@
* <p>Once the bugreport is finished dumpstate has already generated the final files, so
* changing the name would have no effect.
*/
- void onBugreportFinished(int id) {
+ void onBugreportFinished() {
if (mInfoName != null) {
mInfoName.setEnabled(false);
mInfoName.setText(mSavedName);
@@ -1684,7 +1589,7 @@
this.id = id;
this.pid = pid;
this.name = name;
- this.max = max;
+ this.max = this.realMax = max;
}
/**
@@ -1750,14 +1655,17 @@
public String toString() {
final float percent = ((float) progress * 100 / max);
final float realPercent = ((float) realProgress * 100 / realMax);
- return "id: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
- + "\n\ttitle: " + title + "\n\tdescription: " + description
- + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
+ return "\tid: " + id + ", pid: " + pid + ", name: " + name + ", finished: " + finished
+ + "\n\ttitle: " + title
+ + "\n\tdescription: " + description
+ + "\n\tfile: " + bugreportFile
+ + "\n\tscreenshots: " + screenshotFiles
+ "\n\tprogress: " + progress + "/" + max + " (" + percent + ")"
- + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent + ")"
+ + "\n\treal progress: " + realProgress + "/" + realMax + " (" + realPercent
+ + ")"
+ "\n\tlast_update: " + getFormattedLastUpdate()
- + "\naddingDetailsToZip: " + addingDetailsToZip
- + " addedDetailsToZip: " + addedDetailsToZip;
+ + "\n\taddingDetailsToZip: " + addingDetailsToZip + " addedDetailsToZip: "
+ + addedDetailsToZip;
}
// Parcelable contract
@@ -1823,16 +1731,118 @@
return path == null ? null : new File(path);
}
+ @SuppressWarnings("unused")
public static final Parcelable.Creator<BugreportInfo> CREATOR =
new Parcelable.Creator<BugreportInfo>() {
+ @Override
public BugreportInfo createFromParcel(Parcel source) {
return new BugreportInfo(source);
}
+ @Override
public BugreportInfo[] newArray(int size) {
return new BugreportInfo[size];
}
};
}
+
+ private final class DumpstateListener extends IDumpstateListener.Stub
+ implements DeathRecipient {
+
+ private final BugreportInfo info;
+ private IDumpstateToken token;
+
+ DumpstateListener(BugreportInfo info) {
+ this.info = info;
+ }
+
+ /**
+ * Connects to the {@code dumpstate} binder to receive updates.
+ */
+ boolean connect() {
+ if (token != null) {
+ Log.d(TAG, "connect(): " + info.id + " already connected");
+ return true;
+ }
+ final IBinder service = ServiceManager.getService("dumpstate");
+ if (service == null) {
+ Log.d(TAG, "dumpstate service not bound yet");
+ return true;
+ }
+ final IDumpstate dumpstate = IDumpstate.Stub.asInterface(service);
+ try {
+ token = dumpstate.setListener("Shell", this);
+ if (token != null) {
+ token.asBinder().linkToDeath(this, 0);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not set dumpstate listener: " + e);
+ }
+ return token != null;
+ }
+
+ @Override
+ public void binderDied() {
+ if (!info.finished) {
+ // TODO: linkToDeath() might be called BEFORE Shell received the
+ // BUGREPORT_FINISHED broadcast, in which case the statements below
+ // spam logcat (but are harmless).
+ // The right, long-term solution is to provide an onFinished() callback
+ // on IDumpstateListener and call it instead of using a broadcast.
+ Log.w(TAG, "Dumpstate process died:\n" + info);
+ stopProgress(info.id);
+ }
+ token.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void onProgressUpdated(int progress) throws RemoteException {
+ /*
+ * Checks whether the progress changed in a way that should be displayed to the user:
+ * - info.progress / info.max represents the displayed progress
+ * - info.realProgress / info.realMax represents the real progress
+ * - since the real progress can decrease, the displayed progress is only updated if it
+ * increases
+ * - the displayed progress is capped at a maximum (like 99%)
+ */
+ info.realProgress = progress;
+ final int oldPercentage = (CAPPED_MAX * info.progress) / info.max;
+ int newPercentage = (CAPPED_MAX * info.realProgress) / info.realMax;
+ int max = info.realMax;
+
+ if (newPercentage > CAPPED_PROGRESS) {
+ progress = newPercentage = CAPPED_PROGRESS;
+ max = CAPPED_MAX;
+ }
+
+ if (newPercentage > oldPercentage) {
+ if (DEBUG) {
+ if (progress != info.progress) {
+ Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+ + ") from " + info.progress + " to " + progress);
+ }
+ if (max != info.max) {
+ Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+ + ") from " + info.max + " to " + max);
+ }
+ }
+ info.progress = progress;
+ info.max = max;
+ info.lastUpdate = System.currentTimeMillis();
+
+ updateProgress(info);
+ }
+ }
+
+ @Override
+ public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+ Log.d(TAG, "onMaxProgressUpdated: " + maxProgress);
+ info.realMax = maxProgress;
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("token: "); pw.println(token);
+ }
+ }
}
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index f6e558f..15ce90f 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -40,8 +40,7 @@
private static final String TAG = "BugreportReceiver";
/**
- * Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are
- * roughly 17MB of disk space.
+ * Always keep the newest 8 bugreport files.
*/
private static final int MIN_KEEP_COUNT = 8;
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index b4bfb01..4e3744a 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -33,7 +33,6 @@
import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
-import static com.android.shell.BugreportProgressService.POLLING_FREQUENCY;
import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
import static org.junit.Assert.assertEquals;
@@ -65,6 +64,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
@@ -116,7 +116,7 @@
private static final String TAG = "BugreportReceiverTest";
// Timeout for UI operations, in milliseconds.
- private static final int TIMEOUT = (int) POLLING_FREQUENCY * 4;
+ private static final int TIMEOUT = (int) (5 * DateUtils.SECOND_IN_MILLIS);
// Timeout for when waiting for a screenshot to finish.
private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
@@ -209,6 +209,12 @@
}
}
+ /*
+ * TODO: this test is incomplete because:
+ * - the assertProgressNotification() is not really asserting the progress because the
+ * UI automation API doesn't provide a way to check the notification progress bar value
+ * - it should use the binder object instead of SystemProperties to update progress
+ */
@Test
public void testProgress() throws Exception {
resetProperties();
@@ -227,7 +233,6 @@
// Make sure progress never goes back...
SystemProperties.set(MAX_PROPERTY, "2000");
- sleep(POLLING_FREQUENCY + DateUtils.SECOND_IN_MILLIS);
assertProgressNotification(NAME, 95.00f);
SystemProperties.set(PROGRESS_PROPERTY, "1000");
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e07d865..0b5383a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -171,6 +171,8 @@
<!-- shortcut manager -->
<uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
+ <uses-permission android:name="android.permission.MODIFY_THEME_OVERLAY" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java
new file mode 100644
index 0000000..af55e8b
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FragmentBase.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * Interface to deal with lack of multiple inheritance
+ *
+ * This interface is designed to be used as a base class for plugin interfaces
+ * that need fragment methods. Plugins should not extend Fragment directly, so
+ * plugins that are fragments should be extending PluginFragment, but in SysUI
+ * these same versions should extend Fragment directly.
+ *
+ * Only methods that are on Fragment should be included here.
+ */
+public interface FragmentBase {
+ View getView();
+ Context getContext();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
new file mode 100644
index 0000000..a9d1fa9
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+
+public abstract class PluginFragment extends Fragment implements Plugin {
+
+ private static final String KEY_PLUGIN_PACKAGE = "plugin_package_name";
+ private Context mPluginContext;
+
+ @Override
+ public void onCreate(Context sysuiContext, Context pluginContext) {
+ mPluginContext = pluginContext;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ Context sysuiContext = getContext();
+ Context pluginContext = recreatePluginContext(sysuiContext, savedInstanceState);
+ onCreate(sysuiContext, pluginContext);
+ }
+ if (mPluginContext == null) {
+ throw new RuntimeException("PluginFragments must call super.onCreate("
+ + "Context sysuiContext, Context pluginContext)");
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_PLUGIN_PACKAGE, getContext().getPackageName());
+ }
+
+ private Context recreatePluginContext(Context sysuiContext, Bundle savedInstanceState) {
+ final String pkg = savedInstanceState.getString(KEY_PLUGIN_PACKAGE);
+ try {
+ ApplicationInfo appInfo = sysuiContext.getPackageManager().getApplicationInfo(pkg, 0);
+ return PluginManager.getInstance(sysuiContext).getContext(appInfo, pkg);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException("Plugin with invalid package? " + pkg, e);
+ }
+ }
+
+ @Override
+ public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
+ return super.getLayoutInflater(savedInstanceState).cloneInContext(mPluginContext);
+ }
+
+ /**
+ * Should only be called after {@link Plugin#onCreate(Context, Context)}.
+ */
+ @Override
+ public Context getContext() {
+ return mPluginContext != null ? mPluginContext : super.getContext();
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index c64b188..62d3ce4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -158,7 +158,11 @@
case PLUGIN_DISCONNECTED:
if (DEBUG) Log.d(TAG, "onPluginDisconnected");
mListener.onPluginDisconnected((T) msg.obj);
- ((T) msg.obj).onDestroy();
+ if (!(msg.obj instanceof PluginFragment)) {
+ // Only call onDestroy for plugins that aren't fragments, as fragments
+ // will get the onDestroy as part of the fragment lifecycle.
+ ((T) msg.obj).onDestroy();
+ }
break;
default:
super.handleMessage(msg);
@@ -186,7 +190,11 @@
for (int i = mPlugins.size() - 1; i >= 0; i--) {
PluginInfo<T> plugin = mPlugins.get(i);
mListener.onPluginDisconnected(plugin.mPlugin);
- plugin.mPlugin.onDestroy();
+ if (!(plugin.mPlugin instanceof PluginFragment)) {
+ // Only call onDestroy for plugins that aren't fragments, as fragments
+ // will get the onDestroy as part of the fragment lifecycle.
+ plugin.mPlugin.onDestroy();
+ }
}
mPlugins.clear();
handleQueryPlugins(null);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index 85f2e2a..60cf312 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -18,6 +18,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Build;
import android.os.HandlerThread;
@@ -26,6 +28,7 @@
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import dalvik.system.PathClassLoader;
@@ -163,6 +166,16 @@
return mParentClassLoader;
}
+ public Context getAllPluginContext(Context context) {
+ return new PluginContextWrapper(context,
+ new AllPluginClassLoader(context.getClassLoader()));
+ }
+
+ public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
+ ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
+ return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
+ }
+
public static PluginManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new PluginManager(context.getApplicationContext());
@@ -170,6 +183,28 @@
return sInstance;
}
+ private class AllPluginClassLoader extends ClassLoader {
+ public AllPluginClassLoader(ClassLoader classLoader) {
+ super(classLoader);
+ }
+
+ @Override
+ public Class<?> loadClass(String s) throws ClassNotFoundException {
+ try {
+ return super.loadClass(s);
+ } catch (ClassNotFoundException e) {
+ for (ClassLoader classLoader : mClassLoaders.values()) {
+ try {
+ return classLoader.loadClass(s);
+ } catch (ClassNotFoundException e1) {
+ // Will re-throw e if all fail.
+ }
+ }
+ throw e;
+ }
+ }
+ }
+
@VisibleForTesting
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
@@ -180,7 +215,6 @@
}
}
-
// This allows plugins to include any libraries or copied code they want by only including
// classes from the plugin library.
private static class ClassLoaderFilter extends ClassLoader {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
similarity index 93%
rename from packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
rename to packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 4947863..a9874fc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -25,17 +25,21 @@
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
-public abstract class QSContainer extends FrameLayout {
+import com.android.systemui.plugins.FragmentBase;
+
+/**
+ * Fragment that contains QS in the notification shade. Most of the interface is for
+ * handling the expand/collapsing of the view interaction.
+ */
+public interface QS extends FragmentBase {
public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
// This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
// change in incompatible ways.
- public static final int VERSION = 3;
+ public static final int VERSION = 4;
- public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
+ String TAG = "QS";
public abstract void setPanelView(HeightListener notificationPanelView);
public abstract BaseStatusBarHeader getHeader();
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
index c8b4fd0..cff770a 100644
--- a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
+++ b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml
@@ -16,8 +16,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingTop="24dp"
+ android:paddingBottom="54dp"
android:orientation="vertical"
- android:id="@+id/recents_container">
+ android:id="@+id/recents_container"
+ android:background="#99000000">
<include layout="@layout/recents_stack_action_button" />
<FrameLayout
android:layout_width="match_parent"
@@ -26,7 +29,6 @@
android:layout_marginLeft="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="12dp"
- android:layout_marginBottom="5dp"
android:gravity="center">
</FrameLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 7af247e..9ab8ac63 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<!-- Height is 0 because it will be managed by the QSContainer manually -->
+<!-- Height is 0 because it will be managed by the QS manually -->
<com.android.systemui.qs.customize.QSCustomizer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0339e03..f09657f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,15 +39,15 @@
android:clipToPadding="false"
android:clipChildren="false">
- <com.android.systemui.PluginInflateContainer
- android:id="@+id/qs_auto_reinflate_container"
+ <FrameLayout
+ android:id="@+id/qs_frame"
android:layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:clipToPadding="false"
android:clipChildren="false"
- systemui:viewType="com.android.systemui.plugins.qs.QSContainer" />
+ systemui:viewType="com.android.systemui.plugins.qs.QS" />
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ea070b3..5294c9c 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Maak <xliff:g id="ID_1">%s</xliff:g>-instellings oop."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Wysig volgorde van instellings."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 837d677..601930a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"የ<xliff:g id="ID_1">%s</xliff:g> ቅንብሮችን ክፈት።"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ዘርጋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f207dbc1..502a94e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -656,6 +656,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"فتح إعدادات <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"تعديل ترتيب الإعدادات."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index c4b0f73..1bc9e59 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını açın."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sıralanmasını redaktə edin."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index e70e485..8105d9e 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 7f7a67f..83c67d4 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 16dfeeb..bf3a614 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отваряне на настройките за <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Редактиране на подредбата на настройките."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index f8ee362..bd599bc 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> সেটিংস খুলুন৷"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"প্রসারিত করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 0e91713..5ba720c 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -652,6 +652,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d258943..927e75b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Obre la configuració per a <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edita l\'ordre de la configuració."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 845c8b5..69629a9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otevřít nastavení aplikace <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upravit pořadí nastavení."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbalit"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bb340a6..8e34bd0 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -263,7 +263,7 @@
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"Forstyr ikke"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string>
- <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun alarmer"</string>
<string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Total stilhed"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string>
@@ -356,7 +356,7 @@
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Helt lydløs. Denne handling slukker også skærmlæsere."</string>
<string name="interruption_level_none" msgid="6000083681244492992">"Total stilhed"</string>
<string name="interruption_level_priority" msgid="6426766465363855505">"Kun prioritet"</string>
- <string name="interruption_level_alarms" msgid="5226306993448328896">"Kun Alarmer"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"Kun alarmer"</string>
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"Total\nstilhed"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åbn <xliff:g id="ID_1">%s</xliff:g>-indstillinger."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediger rækkefølgen af indstillinger."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Udvid"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index faabbfa..b3a457d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Einstellungen für <xliff:g id="ID_1">%s</xliff:g> öffnen."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Reihenfolge der Einstellungen bearbeiten."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Maximieren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0f5f447..050d7f8 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Άνοιγμα ρυθμίσεων <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Επεξεργασία σειράς ρυθμίσεων."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 14d2a19..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 14d2a19..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 14d2a19..9aca3cc 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Open <xliff:g id="ID_1">%s</xliff:g> settings."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expand"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3b92a3a..90c2ca1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configuración de <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar orden de configuración"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 600d7d5..0a45ac1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir ajustes de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Cambiar el orden de los ajustes."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Mostrar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 884eac5..84fadb2 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ava teenuse <xliff:g id="ID_1">%s</xliff:g> seaded."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muuda seadete järjestust."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index b5e6696..d6578a2 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ireki <xliff:g id="ID_1">%s</xliff:g> ezarpenak."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editatu ezarpenen ordena."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Zabaldu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 866904c..e00c5b5 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"باز کردن تنظیمات <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ویرایش ترتیب تنظیمات."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"بزرگ کردن"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 144704d..08572fe 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Avaa kohteen <xliff:g id="ID_1">%s</xliff:g> asetukset."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Muokkaa asetusten järjestystä."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index b5c227e..830bfa7 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 008d061..3b138c2 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Ouvrir les paramètres <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Développer"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index cca60a8..579335d 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir a configuración de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a orde das opcións de configuración."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 558a90a..48a6d0f 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> સેટિંગ્સ ખોલો."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"વિસ્તૃત કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1fff051..f482caaa 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index ae7e0c4..7ff63bd 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvaranje postavki za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uređivanje redoslijeda postavki."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ec62e1c..bd0805b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"A(z) <xliff:g id="ID_1">%s</xliff:g> beállításainak megnyitása."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Beállítások sorrendjének szerkesztése."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 80cb977..07966cf 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -421,7 +421,7 @@
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Ավելի արագ ստացեք ծանուցումները"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Տեսեք դրանք մինչև ապակողպելը"</string>
- <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ, շնորհակալություն"</string>
+ <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ոչ"</string>
<string name="hidden_notifications_setup" msgid="41079514801976810">"Կարգավորել"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="volume_zen_end_now" msgid="3179845345429841822">"Ավարտել"</string>
@@ -430,7 +430,7 @@
<string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
<string name="screen_pinning_description" msgid="7238941806855968768">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ կոճակը:"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string>
- <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ, շնորհակալություն"</string>
+ <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string>
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Բացել <xliff:g id="ID_1">%s</xliff:g> կարգավորումները:"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Խմբագրել կարգավորումների հերթականությունը:"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 93960e8..6444ae5 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka setelan <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit urutan setelan."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Luaskan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 71ef4bb..7e08a01 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Opna <xliff:g id="ID_1">%s</xliff:g> stillingar."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Breyta röð stillinga."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 12d0ed6..8ffb10d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Apri le impostazioni <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifica l\'ordine delle impostazioni."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Espandi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f565603..a6d7983 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -652,6 +652,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"פתיחת הגדרות של <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"עריכת סדר ההגדרות."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 37bea17..6ef9f73 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> の設定を開きます。"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"設定の順序を編集します。"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 15f5d63..695279d 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> პარამეტრების გახსნა."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"პარამეტრების მიმდევრობის რედაქტირება."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 477ab82..ba71182 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> параметрлерін ашу."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Параметрлер тәртібін өзгерту."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 45771d9..b222555 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"បើការកំណត់ <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"កែលំដាប់ការកំណត់"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 87c48dd..b2a6f27 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3e0cdfe..cefb57a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> 설정 열기"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"설정 순서 수정"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 2d8be38..e013c6b 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> жөндөөлөрүн ачуу."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Жөндөөлөрдүн иретин өзгөртүү."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 93098ad..94e789a 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"ເປີດການຕັ້ງຄ່າ <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 02e614c..5af5979 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -652,6 +652,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atidaryti „<xliff:g id="ID_1">%s</xliff:g>“ nustatymus."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Redaguoti nustatymų tvarką."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Išskleisti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 82f5f22..503c8c8 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Atvērt <xliff:g id="ID_1">%s</xliff:g> iestatījumus."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Rediģēt iestatījumu secību."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index fcaa26f..62fc350 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отворете ги поставките на <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Уредете го редоследот на поставките."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 44d76d5..9e7d2f2 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ക്രമീകരണം തുറക്കുക."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"വികസിപ്പിക്കുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 1c7bc38..04fb4c2 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> тохиргоог нээнэ үү."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Тохиргооны дарааллыг өөрчилнө үү."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 71d6677..a21019a 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग्ज उघडा."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग्जचा क्रम संपादित करा."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index bc9d79f..ce94295 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buka tetapan <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edit susunan tetapan."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 37c002c..8ab1de0 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ဆက်တင်များကို ဖွင့်ပါ။"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ချဲ့ရန်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 025c270..c6312e1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Åpne <xliff:g id="ID_1">%s</xliff:g>-innstillingene."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Endre rekkefølgen på innstillingene."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Vis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 3ed5782..f87223c 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सम्बन्धी सेटिङहरूलाई खोल्नुहोस्।"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"विस्तृत गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 13ef0f6..8217ee5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -235,7 +235,7 @@
<string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
- <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele data zijn onderbroken"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
<string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
@@ -310,7 +310,7 @@
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Meldingen"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Zaklamp"</string>
- <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele gegevens"</string>
+ <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobiele data"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Datagebruik"</string>
<string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Resterende gegevens"</string>
<string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Limiet overschreden"</string>
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 553b604..f25662b 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ਵਿਸਤਾਰ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index cc5b693..78c6102 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -652,6 +652,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otwórz ustawienia: <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Edytuj kolejność ustawień."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ef07edc..0dbdcb9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 5c7ea4f..d037cda 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir as definições de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar a ordem das definições."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ef07edc..0dbdcb9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Abrir configurações de <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0d42645..e33ebb5 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -652,6 +652,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Deschideți setările <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Editați ordinea setărilor."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Extindeți"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9adc9fe..0fbb0bd 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Открыть настройки <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Изменить порядок быстрых настроек."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Развернуть"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 6739ea1..c4d2378 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> සැකසීම් විවෘත කරන්න."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"දිග හරින්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 44881bd..23daf91 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvoriť nastavenia <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Upraviť poradie nastavení"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index cc11704..90985e7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Odpri nastavitve za <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Uredi vrstni red nastavitev."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Razširi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 55598bd..9616c07 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Hap cilësimet e <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Modifiko rendin e cilësimeve."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 22bd853..667c65d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Отвори подешавања за <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Измени редослед подешавања."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 87acdb3..0a95017 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Öppna <xliff:g id="ID_1">%s</xliff:g>-inställningarna."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ändra ordning på inställningarna."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index cc4391ce..afc5ee4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Fungua mipangilio ya <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Badilisha orodha ya mipangilio."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Panua"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 2d3c27f..99b8439 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> அமைப்புகளைத் திற."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 9fa3f86..c1aeb09b 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> సెట్టింగ్లను తెరవండి."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"సెట్టింగ్ల క్రమాన్ని సవరించండి."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"విస్తరింపజేయి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f59e69b..0c461b4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"เปิดการตั้งค่า <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"แก้ไขลำดับการตั้งค่า"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 2d978c4..caa9f97 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Buksan ang mga setting ng <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e3827f7..030c97f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ayarlarını aç."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Ayarların sırasını düzenle."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index fd627cc..c086fff 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -654,6 +654,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Відкрити налаштування <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змінити порядок налаштувань."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Розгорнути"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 415c5b6..ff46ad3 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> ترتیبات کھولیں۔"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"پھیلائیں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index aaea5e5..f2d2661 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> sozlamalarini ochish."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Sozlamalar tartibini o‘zgartirish."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Yoyish"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4ae3370..48b1e4f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Mở cài đặt <xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Chỉnh sửa thứ tự cài đặt."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7c7bc4a..94c3af1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"打开<xliff:g id="ID_1">%s</xliff:g>设置。"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"修改设置顺序。"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e41a24b..5785af9 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -650,6 +650,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟<xliff:g id="ID_1">%s</xliff:g>設定頁面。"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定次序。"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 51e27a3..6562b39 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"開啟「<xliff:g id="ID_1">%s</xliff:g>」設定。"</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"編輯設定順序。"</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 887da2e..e3c419b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -648,6 +648,5 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Vula izilungiselelo ze-<xliff:g id="ID_1">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Hlela uhlelo lwezilungiselelo."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <!-- no translation found for pip_phone_expand (5889780005575693909) -->
- <skip />
+ <string name="pip_phone_expand" msgid="5889780005575693909">"Nweba"</string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9eea375..0f5d37e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -48,6 +48,12 @@
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
+ <!-- Vibrator pattern for camera gesture launch. -->
+ <integer-array translatable="false" name="config_cameraLaunchGestureVibePattern">
+ <item>0</item>
+ <item>400</item>
+ </integer-array>
+
<!-- How many icons may be shown at once in the system bar. Includes any
slots that may be reused for things like IME control. -->
<integer name="config_maxNotificationIcons">5</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 37a7e38..331d09e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1698,20 +1698,35 @@
not appear on production builds ever. -->
<string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
- <!-- PIP tap once to break through to the activity. Non-translatable since it should
+ <!-- PIP tap once to break through to the activity title. Non-translatable since it should
not appear on production builds ever. -->
<string name="pip_tap_through_title" translatable="false">Tap to interact</string>
- <!-- PIP tap once to break through to the activity. Non-translatable since it should
+ <!-- PIP tap once to break through to the activity description. Non-translatable since it should
not appear on production builds ever. -->
<string name="pip_tap_through_summary" translatable="false">Tap once to interact with the activity</string>
- <!-- PIP snap to closest edge. Non-translatable since it should
+ <!-- PIP snap to closest edge title. Non-translatable since it should
not appear on production builds ever. -->
<string name="pip_snap_mode_edge_title" translatable="false">Snap to closest edge</string>
- <!-- PIP snap to closest edge. Non-translatable since it should
+ <!-- PIP snap to closest edge description. Non-translatable since it should
not appear on production builds ever. -->
<string name="pip_snap_mode_edge_summary" translatable="false">Snap to the closest edge</string>
+ <!-- PIP allow minimize title. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_allow_minimize_title" translatable="false">Allow PIP to minimize</string>
+
+ <!-- PIP allow minimize description. Non-translatable since it should
+ not appear on production builds ever. -->
+ <string name="pip_allow_minimize_summary" translatable="false">Allow PIP to minimize slightly offscreen</string>
+
+ <!-- Tuner string -->
+ <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
+ <!-- Tuner string -->
+ <string name="theme" translatable="false">Theme</string>
+ <!-- Tuner string -->
+ <string name="default_theme" translatable="false">Default</string>
+
</resources>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index ce636cd..18cb930 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -23,5 +23,10 @@
android:key="power_notification_controls"
android:title="@string/tuner_full_importance_settings"
android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
+e
+ <com.android.systemui.tuner.ThemePreference
+ android:key="theme"
+ android:title="@string/theme"
+ android:summary="%s" />
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index f09d6e9..74d5d6c 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -149,6 +149,12 @@
android:summary="@string/pip_snap_mode_edge_summary"
sysui:defValue="false" />
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="pip_allow_minimize"
+ android:title="@string/pip_allow_minimize_title"
+ android:summary="@string/pip_allow_minimize_summary"
+ sysui:defValue="false" />
+
</PreferenceScreen>
<PreferenceScreen
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index e1d6a94..c4698c3 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -32,8 +32,8 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
-import android.os.Looper;
import android.provider.Settings;
+
import com.android.systemui.statusbar.policy.BatteryController;
public class BatteryMeterDrawable extends Drawable implements
@@ -182,13 +182,13 @@
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
updateShowPercent();
- mBatteryController.addStateChangedCallback(this);
+ mBatteryController.addCallback(this);
}
public void stopListening() {
mListening = false;
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
- mBatteryController.removeStateChangedCallback(this);
+ mBatteryController.removeCallback(this);
}
public void disableShowPercent() {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 4f3ffde..ef1c25d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,7 +17,6 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.os.Handler;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.View;
@@ -73,7 +72,7 @@
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
- mBatteryController.addStateChangedCallback(this);
+ mBatteryController.addCallback(this);
mDrawable.startListening();
TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
}
@@ -81,7 +80,7 @@
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mBatteryController.removeStateChangedCallback(this);
+ mBatteryController.removeCallback(this);
mDrawable.stopListening();
TunerService.get(getContext()).removeTunable(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 9a64a41..3a8536b 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -16,7 +16,7 @@
package com.android.systemui;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -66,7 +66,7 @@
UserInfo currentUser;
try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUser = ActivityManager.getService().getCurrentUser();
} catch (RemoteException e) {
return;
}
@@ -96,7 +96,7 @@
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
UserInfo currentUser;
try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUser = ActivityManager.getService().getCurrentUser();
} catch (RemoteException e) {
Log.e(TAG, "Couldn't wipe session because ActivityManager is dead");
return;
@@ -122,12 +122,12 @@
try {
if (newGuest == null) {
Log.e(TAG, "Could not create new guest, switching back to system user");
- ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM);
+ ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
userManager.removeUser(currentUser.id);
WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
return;
}
- ActivityManagerNative.getDefault().switchUser(newGuest.id);
+ ActivityManager.getService().switchUser(newGuest.id);
userManager.removeUser(currentUser.id);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't wipe session because ActivityManager or WindowManager is dead");
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 99e7876..6802fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,9 +29,11 @@
import android.os.UserHandle;
import android.util.Log;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyboard.KeyboardUI;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.media.RingtonePlayer;
+import com.android.systemui.pip.PipUI;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
@@ -42,7 +44,6 @@
import com.android.systemui.statusbar.SystemBars;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.usb.StorageNotification;
import com.android.systemui.volume.VolumeUI;
@@ -61,6 +62,7 @@
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
+ FragmentService.class,
TunerService.class,
KeyguardViewMediator.class,
Recents.class,
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index b1f454e..965ded5 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -35,8 +35,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
/**
* Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index b39803a..f8b73a1 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -22,10 +22,10 @@
import java.util.ArrayList;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
-import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent;
/**
* Collects touch, sensor and phone events and converts the data to
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index b3038b9..870d4d1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -78,10 +78,10 @@
log("pulseFinish");
}
- public static void traceNotificationPulse(Context context, long instance) {
+ public static void traceNotificationPulse(Context context) {
if (!ENABLED) return;
init(context);
- log("notificationPulse instance=" + instance);
+ log("notificationPulse");
sNotificationPulseStats.append();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index bb4ea2d..9cc927d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -34,7 +34,7 @@
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.statusbar.phone.DozeParameters;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 9df8113..9f26b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -87,6 +87,7 @@
mNotificationPulseTime = SystemClock.elapsedRealtime();
if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
+ DozeLog.traceNotificationPulse(mContext);
}
private void onWhisper() {
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
new file mode 100644
index 0000000..5f27b74
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.fragments;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
+import android.app.FragmentManager;
+import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.app.FragmentManagerNonConfig;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.plugins.PluginManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class FragmentHostManager {
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Context mContext;
+ private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>();
+ private final View mRootView;
+ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges();
+ private final FragmentService mManager;
+
+ private FragmentController mFragments;
+ private FragmentLifecycleCallbacks mLifecycleCallbacks;
+
+ FragmentHostManager(Context context, FragmentService manager, View rootView) {
+ mContext = PluginManager.getInstance(context).getAllPluginContext(context);
+ mManager = manager;
+ mRootView = rootView;
+ mConfigChanges.applyNewConfig(context.getResources());
+ createFragmentHost(null);
+ }
+
+ private void createFragmentHost(Parcelable savedState) {
+ mFragments = FragmentController.createController(new HostCallbacks());
+ mFragments.attachHost(null);
+ // TODO: Remove non-staticness from FragmentLifecycleCallbacks (hopefully).
+ mLifecycleCallbacks = mFragments.getFragmentManager().new FragmentLifecycleCallbacks() {
+ @Override
+ public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
+ Bundle savedInstanceState) {
+ FragmentHostManager.this.onFragmentViewCreated(f);
+ }
+
+ @Override
+ public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
+ FragmentHostManager.this.onFragmentViewDestroyed(f);
+ }
+ };
+ mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks,
+ true);
+ if (savedState != null) {
+ mFragments.restoreAllState(savedState, (FragmentManagerNonConfig) null);
+ }
+ // For now just keep all fragments in the resumed state.
+ mFragments.dispatchCreate();
+ mFragments.dispatchStart();
+ mFragments.dispatchResume();
+ }
+
+ private Parcelable destroyFragmentHost() {
+ mFragments.dispatchPause();
+ Parcelable p = mFragments.saveAllState();
+ mFragments.dispatchStop();
+ mFragments.dispatchDestroy();
+ mFragments.getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
+ return p;
+ }
+
+ public void addTagListener(String tag, FragmentListener listener) {
+ ArrayList<FragmentListener> listeners = mListeners.get(tag);
+ if (listeners == null) {
+ listeners = new ArrayList<>();
+ mListeners.put(tag, listeners);
+ }
+ listeners.add(listener);
+ Fragment current = getFragmentManager().findFragmentByTag(tag);
+ if (current != null && current.getView() != null) {
+ listener.onFragmentViewCreated(tag, current);
+ }
+ }
+
+ // Shouldn't generally be needed, included for completeness sake.
+ public void removeTagListener(String tag, FragmentListener listener) {
+ ArrayList<FragmentListener> listeners = mListeners.get(tag);
+ if (listeners != null && listeners.remove(listener) && listeners.size() == 0) {
+ mListeners.remove(tag);
+ }
+ }
+
+ private void onFragmentViewCreated(Fragment fragment) {
+ String tag = fragment.getTag();
+
+ ArrayList<FragmentListener> listeners = mListeners.get(tag);
+ if (listeners != null) {
+ listeners.forEach((listener) -> listener.onFragmentViewCreated(tag, fragment));
+ }
+ }
+
+ private void onFragmentViewDestroyed(Fragment fragment) {
+ String tag = fragment.getTag();
+
+ ArrayList<FragmentListener> listeners = mListeners.get(tag);
+ if (listeners != null) {
+ listeners.forEach((listener) -> listener.onFragmentViewDestroyed(tag, fragment));
+ }
+ }
+
+ /**
+ * Called when the configuration changed, return true if the fragments
+ * should be recreated.
+ */
+ protected void onConfigurationChanged(Configuration newConfig) {
+ if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+ // Save the old state.
+ Parcelable p = destroyFragmentHost();
+ // Generate a new fragment host and restore its state.
+ createFragmentHost(p);
+ } else {
+ mFragments.dispatchConfigurationChanged(newConfig);
+ }
+ }
+
+ private void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ // TODO: Do something?
+ }
+
+ private View findViewById(int id) {
+ return mRootView.findViewById(id);
+ }
+
+ /**
+ * Note: Values from this shouldn't be cached as they can change after config changes.
+ */
+ public FragmentManager getFragmentManager() {
+ return mFragments.getFragmentManager();
+ }
+
+ public interface FragmentListener {
+ void onFragmentViewCreated(String tag, Fragment fragment);
+
+ // The facts of lifecycle
+ // When a fragment is destroyed, you should not talk to it any longer.
+ default void onFragmentViewDestroyed(String tag, Fragment fragment) {
+ }
+ }
+
+ public static FragmentHostManager get(View view) {
+ try {
+ return ((SystemUIApplication) view.getContext().getApplicationContext())
+ .getComponent(FragmentService.class).getFragmentHostManager(view);
+ } catch (ClassCastException e) {
+ // TODO: Some auto handling here?
+ throw e;
+ }
+ }
+
+ class HostCallbacks extends FragmentHostCallback<FragmentHostManager> {
+ public HostCallbacks() {
+ super(mContext, FragmentHostManager.this.mHandler, 0);
+ }
+
+ @Override
+ public FragmentHostManager onGetHost() {
+ return FragmentHostManager.this;
+ }
+
+ @Override
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ FragmentHostManager.this.dump(prefix, fd, writer, args);
+ }
+
+ @Override
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return true; // True for now.
+ }
+
+ @Override
+ public LayoutInflater onGetLayoutInflater() {
+ return LayoutInflater.from(mContext);
+ }
+
+ @Override
+ public boolean onUseFragmentManagerInflaterFactory() {
+ return true;
+ }
+
+ @Override
+ public boolean onHasWindowAnimations() {
+ return false;
+ }
+
+ @Override
+ public int onGetWindowAnimations() {
+ return 0;
+ }
+
+ @Override
+ public void onAttachFragment(Fragment fragment) {
+ }
+
+ @Override
+ @Nullable
+ public View onFindViewById(int id) {
+ return FragmentHostManager.this.findViewById(id);
+ }
+
+ @Override
+ public boolean onHasView() {
+ return true;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
new file mode 100644
index 0000000..85cde10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.fragments;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
+
+/**
+ * Holds a map of root views to FragmentHostStates and generates them as needed.
+ * Also dispatches the configuration changes to all current FragmentHostStates.
+ */
+public class FragmentService extends SystemUI {
+
+ private static final String TAG = "FragmentService";
+
+ private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
+ private final Handler mHandler = new Handler();
+
+ @Override
+ public void start() {
+ putComponent(FragmentService.class, this);
+ }
+
+ public FragmentHostManager getFragmentHostManager(View view) {
+ View root = view.getRootView();
+ FragmentHostState state = mHosts.get(root);
+ if (state == null) {
+ state = new FragmentHostState(root);
+ mHosts.put(root, state);
+ }
+ return state.getFragmentHostManager();
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ for (FragmentHostState state : mHosts.values()) {
+ state.sendConfigurationChange(newConfig);
+ }
+ }
+
+ private class FragmentHostState {
+ private final View mView;
+
+ private FragmentHostManager mFragmentHostManager;
+
+ public FragmentHostState(View view) {
+ mView = view;
+ mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView);
+ }
+
+ public void sendConfigurationChange(Configuration newConfig) {
+ mHandler.post(() -> handleSendConfigurationChange(newConfig));
+ }
+
+ public FragmentHostManager getFragmentHostManager() {
+ return mFragmentHostManager;
+ }
+
+ private void handleSendConfigurationChange(Configuration newConfig) {
+ mFragmentHostManager.onConfigurationChanged(newConfig);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
new file mode 100644
index 0000000..e107fcd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.fragments;
+
+import android.app.Fragment;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.plugins.FragmentBase;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+
+public class PluginFragmentListener implements PluginListener<Plugin> {
+
+ private static final String TAG = "PluginFragmentListener";
+
+ private final FragmentHostManager mFragmentHostManager;
+ private final PluginManager mPluginManager;
+ private final Class<? extends Fragment> mDefaultClass;
+ private final int mId;
+ private final String mTag;
+ private final Class<? extends FragmentBase> mExpectedInterface;
+
+ public PluginFragmentListener(View view, String tag, int id,
+ Class<? extends Fragment> defaultFragment,
+ Class<? extends FragmentBase> expectedInterface) {
+ mFragmentHostManager = FragmentHostManager.get(view);
+ mPluginManager = PluginManager.getInstance(view.getContext());
+ mExpectedInterface = expectedInterface;
+ mTag = tag;
+ mDefaultClass = defaultFragment;
+ mId = id;
+ }
+
+ public void startListening(String action, int version) {
+ try {
+ setFragment(mDefaultClass.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
+ }
+ mPluginManager.addPluginListener(action, this, version, false /* Only allow one */);
+ }
+
+ public void stopListening() {
+ mPluginManager.removePluginListener(this);
+ }
+
+ private void setFragment(Fragment fragment) {
+ mFragmentHostManager.getFragmentManager().beginTransaction()
+ .replace(mId, fragment, mTag)
+ .commit();
+ }
+
+ @Override
+ public void onPluginConnected(Plugin plugin) {
+ try {
+ mExpectedInterface.cast(plugin);
+ setFragment((Fragment) plugin);
+ } catch (ClassCastException e) {
+ Log.e(TAG, plugin.getClass().getName() + " must be a Fragment and implement "
+ + mExpectedInterface.getName(), e);
+ }
+ }
+
+ @Override
+ public void onPluginDisconnected(Plugin plugin) {
+ try {
+ setFragment(mDefaultClass.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 816d70d..fe9f55f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -136,7 +136,7 @@
@Override // Binder interface
public void onScreenTurnedOn() {
- Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn");
+ Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn");
checkPermission();
mKeyguardViewMediator.onScreenTurnedOn();
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9ae341a..34dc63f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -23,7 +23,6 @@
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.SearchManager;
@@ -285,6 +284,7 @@
private LockPatternUtils mLockPatternUtils;
private boolean mKeyguardDonePending = false;
private boolean mHideAnimationRun = false;
+ private boolean mHideAnimationRunning = false;
private SoundPool mLockSounds;
private int mLockSoundId;
@@ -515,9 +515,7 @@
return;
}
- if (!mKeyguardDonePending) {
- KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
- }
+ tryKeyguardDone(true);
if (strongAuth) {
mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
}
@@ -545,7 +543,8 @@
mKeyguardDonePending = true;
mHideAnimationRun = true;
- mStatusBarKeyguardViewManager.startPreHideAnimation(null /* finishRunnable */);
+ mHideAnimationRunning = true;
+ mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
KEYGUARD_DONE_PENDING_TIMEOUT_MS);
if (strongAuth) {
@@ -565,9 +564,11 @@
public void readyForKeyguardDone() {
Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
if (mKeyguardDonePending) {
+ mKeyguardDonePending = false;
+
// Somebody has called keyguardDonePending before, which means that we are
// authenticated
- KeyguardViewMediator.this.handleKeyguardDone(true /* authenticated */);
+ tryKeyguardDone(true);
}
Trace.endSection();
}
@@ -643,9 +644,7 @@
// Assume keyguard is showing (unless it's disabled) until we know for sure...
setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser()));
- updateInputRestrictedLocked();
- mTrustManager.reportKeyguardShowingChanged();
+ KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
mStatusBarKeyguardViewManager =
SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
@@ -1257,7 +1256,7 @@
*/
public void handleDismiss(boolean allowWhileOccluded) {
if (mShowing && (allowWhileOccluded || !mOccluded)) {
- mStatusBarKeyguardViewManager.dismiss();
+ mStatusBarKeyguardViewManager.dismissAndCollapse();
}
}
@@ -1493,6 +1492,16 @@
}
};
+ private void tryKeyguardDone(boolean authenticated) {
+ if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
+ handleKeyguardDone(authenticated);
+ } else if (!mHideAnimationRun) {
+ mHideAnimationRun = true;
+ mHideAnimationRunning = true;
+ mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
+ }
+ }
+
/**
* @see #keyguardDone
* @see #KEYGUARD_DONE
@@ -1609,7 +1618,7 @@
private void updateActivityLockScreenState() {
Trace.beginSection("KeyguardViewMediator#updateActivityLockScreenState");
try {
- ActivityManagerNative.getDefault().setLockScreenShown(mShowing);
+ ActivityManager.getService().setLockScreenShown(mShowing);
} catch (RemoteException e) {
}
Trace.endSection();
@@ -1671,7 +1680,7 @@
// Don't actually hide the Keyguard at the moment, wait for window
// manager until it tells us it's safe to do so with
// startKeyguardExitAnimation.
- ActivityManagerNative.getDefault().keyguardGoingAway(flags);
+ ActivityManager.getService().keyguardGoingAway(flags);
} catch (RemoteException e) {
Log.e(TAG, "Error while calling WindowManager", e);
}
@@ -1679,6 +1688,11 @@
}
};
+ private final Runnable mHideAnimationFinishedRunnable = () -> {
+ mHideAnimationRunning = false;
+ tryKeyguardDone(true);
+ };
+
/**
* Handle message sent by {@link #hideLocked()}
* @see #HIDE
@@ -1697,16 +1711,10 @@
return;
}
mHiding = true;
- if (mShowing && !mOccluded) {
- if (!mHideAnimationRun) {
- mStatusBarKeyguardViewManager.startPreHideAnimation(mKeyguardGoingAwayRunnable);
- } else {
- mKeyguardGoingAwayRunnable.run();
- }
- } else {
- // Don't try to rely on WindowManager - if Keyguard wasn't showing, window
- // manager won't start the exit animation.
+ if (mShowing && !mOccluded) {
+ mKeyguardGoingAwayRunnable.run();
+ } else {
handleStartKeyguardExitAnimation(
SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
mHideAnimation.getDuration());
@@ -1806,7 +1814,7 @@
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
setShowingLocked(true);
- mStatusBarKeyguardViewManager.verifyUnlock();
+ mStatusBarKeyguardViewManager.dismissAndCollapse();
}
Trace.endSection();
}
@@ -1969,7 +1977,11 @@
}
private void setShowingLocked(boolean showing) {
- if (showing != mShowing) {
+ setShowingLocked(showing, false /* forceCallbacks */);
+ }
+
+ private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+ if (showing != mShowing || forceCallbacks) {
mShowing = showing;
int size = mKeyguardStateCallbacks.size();
for (int i = size - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 7b8d27e..43cfa32 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,7 +16,7 @@
package com.android.systemui.pip.phone;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.view.IWindowManager;
@@ -44,7 +44,7 @@
*/
public void initialize(Context context) {
mContext = context;
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
new file mode 100644
index 0000000..e8e8a4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchGesture.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone;
+
+/**
+ * A generic interface for a touch gesture.
+ */
+public abstract class PipTouchGesture {
+
+ /**
+ * Handle the touch down.
+ */
+ void onDown(PipTouchState touchState) {}
+
+ /**
+ * Handle the touch move, and return whether the event was consumed.
+ */
+ boolean onMove(PipTouchState touchState) {
+ return false;
+ }
+
+ /**
+ * Handle the touch up, and return whether the gesture was consumed.
+ */
+ boolean onUp(PipTouchState touchState) {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index a359380..c6dde46 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -22,6 +22,7 @@
import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -30,9 +31,9 @@
import android.app.ActivityManager.StackInfo;
import android.app.IActivityManager;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -43,7 +44,6 @@
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.os.BackgroundThread;
@@ -64,10 +64,17 @@
private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
private static final String TUNER_KEY_TAP_THROUGH = "pip_tap_through";
private static final String TUNER_KEY_SNAP_MODE_EDGE = "pip_snap_mode_edge";
+ private static final String TUNER_KEY_ALLOW_MINIMIZE = "pip_allow_minimize";
private static final int SNAP_STACK_DURATION = 225;
private static final int DISMISS_STACK_DURATION = 375;
private static final int EXPAND_STACK_DURATION = 225;
+ private static final int MINIMIZE_STACK_MAX_DURATION = 200;
+
+ // The fraction of the stack width that the user has to drag offscreen to minimize the PIP
+ private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f;
+ // The fraction of the stack width that the user has to move when flinging to dismiss the PIP
+ private static final float DISMISS_FLING_DISTANCE_FRACTION = 0.3f;
private final Context mContext;
private final IActivityManager mActivityManager;
@@ -83,10 +90,16 @@
private final PipSnapAlgorithm mSnapAlgorithm;
private PipMotionHelper mMotionHelper;
+ // Allow swiping offscreen to dismiss the PIP
private boolean mEnableSwipeToDismiss = true;
+ // Allow dragging the PIP to a location to close it
private boolean mEnableDragToDismiss = true;
+ // Allow tapping on the PIP to show additional controls
private boolean mEnableTapThrough = false;
+ // Allow snapping the PIP to the closest edge and not the corners of the screen
private boolean mEnableSnapToEdge = false;
+ // Allow the PIP to be "docked" slightly offscreen
+ private boolean mEnableMinimizing = false;
private final Rect mPinnedStackBounds = new Rect();
private final Rect mBoundedPinnedStackBounds = new Rect();
@@ -99,16 +112,16 @@
}
};
- private final PointF mDownTouch = new PointF();
- private final PointF mLastTouch = new PointF();
- private boolean mIsDragging;
- private boolean mIsSwipingToDismiss;
+ // Behaviour states
private boolean mIsTappingThrough;
- private int mActivePointerId;
+ private boolean mIsMinimized;
+ // Touch state
+ private final PipTouchState mTouchState;
private final FlingAnimationUtils mFlingAnimationUtils;
- private VelocityTracker mVelocityTracker;
+ private final PipTouchGesture[] mGestures;
+ // Temporary vars
private final Rect mTmpBounds = new Rect();
/**
@@ -183,13 +196,19 @@
mMenuController.addListener(mMenuListener);
mDismissViewController = new PipDismissViewController(context);
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
+ mTouchState = new PipTouchState(mViewConfig);
mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
+ mGestures = new PipTouchGesture[]{
+ mDragToDismissGesture, mSwipeToDismissGesture, mTapThroughGesture, mMinimizeGesture,
+ mDefaultMovementGesture
+ };
mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler());
registerInputConsumer();
// Register any tuner settings changes
TunerService.get(context).addTunable(this, TUNER_KEY_SWIPE_TO_DISMISS,
- TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE);
+ TUNER_KEY_DRAG_TO_DISMISS, TUNER_KEY_TAP_THROUGH, TUNER_KEY_SNAP_MODE_EDGE,
+ TUNER_KEY_ALLOW_MINIMIZE);
}
@Override
@@ -198,6 +217,8 @@
// Reset back to default
mEnableSwipeToDismiss = true;
mEnableDragToDismiss = true;
+ mEnableMinimizing = false;
+ setMinimizedState(false);
mEnableTapThrough = false;
mIsTappingThrough = false;
mEnableSnapToEdge = false;
@@ -211,6 +232,9 @@
case TUNER_KEY_DRAG_TO_DISMISS:
mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
break;
+ case TUNER_KEY_ALLOW_MINIMIZE:
+ mEnableMinimizing = Integer.parseInt(newValue) != 0;
+ break;
case TUNER_KEY_TAP_THROUGH:
mEnableTapThrough = Integer.parseInt(newValue) != 0;
mIsTappingThrough = false;
@@ -233,6 +257,9 @@
return true;
}
+ // Update the touch state
+ mTouchState.onTouchEvent(ev);
+
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
// Cancel any existing animations on the pinned stack
@@ -241,173 +268,58 @@
}
updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */);
- initOrResetVelocityTracker();
- mVelocityTracker.addMovement(ev);
- mActivePointerId = ev.getPointerId(0);
- mLastTouch.set(ev.getX(), ev.getY());
- mDownTouch.set(mLastTouch);
- mIsDragging = false;
+ for (PipTouchGesture gesture : mGestures) {
+ gesture.onDown(mTouchState);
+ }
try {
mPinnedStackController.setInInteractiveMode(true);
} catch (RemoteException e) {
Log.e(TAG, "Could not set dragging state", e);
}
- if (mEnableDragToDismiss) {
- // TODO: Consider setting a timer such at after X time, we show the dismiss
- // target if the user hasn't already dragged some distance
- mDismissViewController.createDismissTarget();
- }
break;
}
case MotionEvent.ACTION_MOVE: {
- // Update the velocity tracker
- mVelocityTracker.addMovement(ev);
-
- int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- float x = ev.getX(activePointerIndex);
- float y = ev.getY(activePointerIndex);
- float left = mPinnedStackBounds.left + (x - mLastTouch.x);
- float top = mPinnedStackBounds.top + (y - mLastTouch.y);
-
- if (!mIsDragging) {
- // Check if the pointer has moved far enough
- float movement = PointF.length(mDownTouch.x - x, mDownTouch.y - y);
- if (movement > mViewConfig.getScaledTouchSlop()) {
- mIsDragging = true;
- mIsTappingThrough = false;
- mMenuController.hideMenu();
- if (mEnableSwipeToDismiss) {
- // TODO: this check can have some buffer so that we only start swiping
- // after a significant move out of bounds
- mIsSwipingToDismiss = !(mBoundedPinnedStackBounds.left <= left &&
- left <= mBoundedPinnedStackBounds.right) &&
- Math.abs(mDownTouch.x - x) > Math.abs(y - mLastTouch.y);
- }
- if (mEnableDragToDismiss) {
- mDismissViewController.showDismissTarget();
- }
+ for (PipTouchGesture gesture : mGestures) {
+ if (gesture.onMove(mTouchState)) {
+ break;
}
}
-
- if (mIsSwipingToDismiss) {
- // Ignore the vertical movement
- mTmpBounds.set(mPinnedStackBounds);
- mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
- if (!mTmpBounds.equals(mPinnedStackBounds)) {
- mPinnedStackBounds.set(mTmpBounds);
- mMotionHelper.resizeToBounds(mPinnedStackBounds);
- }
- } else if (mIsDragging) {
- // Move the pinned stack
- if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) {
- left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
- mBoundedPinnedStackBounds.right, left));
- top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
- mBoundedPinnedStackBounds.bottom, top));
- }
- mTmpBounds.set(mPinnedStackBounds);
- mTmpBounds.offsetTo((int) left, (int) top);
- if (!mTmpBounds.equals(mPinnedStackBounds)) {
- mPinnedStackBounds.set(mTmpBounds);
- mMotionHelper.resizeToBounds(mPinnedStackBounds);
- }
- }
- mLastTouch.set(ev.getX(), ev.getY());
- break;
- }
- case MotionEvent.ACTION_POINTER_UP: {
- // Update the velocity tracker
- mVelocityTracker.addMovement(ev);
-
- int pointerIndex = ev.getActionIndex();
- int pointerId = ev.getPointerId(pointerIndex);
- if (pointerId == mActivePointerId) {
- // Select a new active pointer id and reset the movement state
- final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
- mActivePointerId = ev.getPointerId(newPointerIndex);
- mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex));
- }
break;
}
case MotionEvent.ACTION_UP: {
- // Update the velocity tracker
- mVelocityTracker.addMovement(ev);
- mVelocityTracker.computeCurrentVelocity(1000,
- ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
- float velocityX = mVelocityTracker.getXVelocity();
- float velocityY = mVelocityTracker.getYVelocity();
- float velocity = PointF.length(velocityX, velocityY);
-
// Update the movement bounds again if the state has changed since the user started
// dragging (ie. when the IME shows)
updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */);
- if (mIsSwipingToDismiss) {
- if (Math.abs(velocityX) > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- flingToDismiss(velocityX);
- } else {
- animateToClosestSnapTarget();
+ for (PipTouchGesture gesture : mGestures) {
+ if (gesture.onUp(mTouchState)) {
+ break;
}
- } else if (mIsDragging) {
- if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- flingToSnapTarget(velocity, velocityX, velocityY);
- } else {
- int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- int x = (int) ev.getX(activePointerIndex);
- int y = (int) ev.getY(activePointerIndex);
- Rect dismissBounds = mEnableDragToDismiss
- ? mDismissViewController.getDismissBounds()
- : null;
- if (dismissBounds != null && dismissBounds.contains(x, y)) {
- animateDismissPinnedStack(dismissBounds);
- } else {
- animateToClosestSnapTarget();
- }
- }
- } else {
- if (mEnableTapThrough) {
- if (!mIsTappingThrough) {
- mMenuController.showMenu();
- mIsTappingThrough = true;
- }
- } else {
- expandPinnedStackToFullscreen();
- }
- }
- if (mEnableDragToDismiss) {
- mDismissViewController.destroyDismissTarget();
}
// Fall through to clean up
}
case MotionEvent.ACTION_CANCEL: {
- mIsDragging = false;
- mIsSwipingToDismiss = false;
try {
mPinnedStackController.setInInteractiveMode(false);
} catch (RemoteException e) {
Log.e(TAG, "Could not set dragging state", e);
}
- recycleVelocityTracker();
break;
}
}
return !mIsTappingThrough;
}
- private void initOrResetVelocityTracker() {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- } else {
- mVelocityTracker.clear();
- }
- }
-
- private void recycleVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
+ /**
+ * @return whether the current touch state is a horizontal drag offscreen.
+ */
+ private boolean isDraggingOffscreen(PipTouchState touchState) {
+ PointF lastDelta = touchState.getLastTouchDelta();
+ PointF downDelta = touchState.getDownTouchDelta();
+ float left = mPinnedStackBounds.left + lastDelta.x;
+ return !(mBoundedPinnedStackBounds.left <= left && left <= mBoundedPinnedStackBounds.right)
+ && Math.abs(downDelta.x) > Math.abs(downDelta.y);
}
/**
@@ -449,6 +361,71 @@
}
/**
+ * Sets the minimized state and notifies the controller.
+ */
+ private void setMinimizedState(boolean isMinimized) {
+ mIsMinimized = isMinimized;
+ try {
+ mPinnedStackController.setIsMinimized(isMinimized);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not set minimized state", e);
+ }
+ }
+
+ /**
+ * @return whether the given {@param pinnedStackBounds} indicates the PIP should be minimized.
+ */
+ private boolean shouldMinimizedPinnedStack() {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ if (mPinnedStackBounds.left < 0) {
+ float offscreenFraction = (float) -mPinnedStackBounds.left / mPinnedStackBounds.width();
+ return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+ } else if (mPinnedStackBounds.right > displaySize.x) {
+ float offscreenFraction = (float) (mPinnedStackBounds.right - displaySize.x) /
+ mPinnedStackBounds.width();
+ return offscreenFraction >= MINIMIZE_OFFSCREEN_FRACTION;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Flings the minimized PIP to the closest minimized snap target.
+ */
+ private void flingToMinimizedSnapTarget(float velocityY) {
+ // We currently only allow flinging the minimized stack up and down, so just lock the
+ // movement bounds to the current stack bounds horizontally
+ Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top,
+ mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom);
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds,
+ 0 /* velocityX */, velocityY);
+ if (!mPinnedStackBounds.equals(toBounds)) {
+ mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
+ toBounds, 0, FAST_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener);
+ mFlingAnimationUtils.apply(mPinnedStackBoundsAnimator, 0,
+ distanceBetweenRectOffsets(mPinnedStackBounds, toBounds),
+ velocityY);
+ mPinnedStackBoundsAnimator.start();
+ }
+ }
+
+ /**
+ * Animates the PIP to the minimized state, slightly offscreen.
+ */
+ private void animateToClosestMinimizedTarget() {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
+ mPinnedStackBounds);
+ mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize);
+ mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
+ toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
+ mUpdatePinnedStackBoundsListener);
+ mPinnedStackBoundsAnimator.start();
+ }
+
+ /**
* Flings the PIP to the closest snap target.
*/
private void flingToSnapTarget(float velocity, float velocityX, float velocityY) {
@@ -478,12 +455,26 @@
}
/**
+ * @return whether the velocity is coincident with the current pinned stack bounds to be
+ * considered a fling to dismiss.
+ */
+ private boolean isFlingToDismiss(float velocityX) {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
+ return (mPinnedStackBounds.right > displaySize.x && velocityX > 0) ||
+ (mPinnedStackBounds.left < 0 && velocityX < 0);
+ }
+
+ /**
* Flings the PIP to dismiss it offscreen.
*/
private void flingToDismiss(float velocityX) {
+ Point displaySize = new Point();
+ mContext.getDisplay().getRealSize(displaySize);
float offsetX = velocityX > 0
- ? mBoundedPinnedStackBounds.right + 2 * mPinnedStackBounds.width()
- : mBoundedPinnedStackBounds.left - 2 * mPinnedStackBounds.width();
+ ? displaySize.x + mPinnedStackBounds.width()
+ : -mPinnedStackBounds.width();
+
Rect toBounds = new Rect(mPinnedStackBounds);
toBounds.offsetTo((int) offsetX, toBounds.top);
if (!mPinnedStackBounds.equals(toBounds)) {
@@ -495,13 +486,7 @@
mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- BackgroundThread.getHandler().post(() -> {
- try {
- mActivityManager.removeStack(PINNED_STACK_ID);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PIP", e);
- }
- });
+ BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
}
});
mPinnedStackBoundsAnimator.start();
@@ -521,13 +506,7 @@
mPinnedStackBoundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- BackgroundThread.getHandler().post(() -> {
- try {
- mActivityManager.removeStack(PINNED_STACK_ID);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PIP", e);
- }
- });
+ BackgroundThread.getHandler().post(PipTouchHandler.this::dismissPinnedStack);
}
});
mPinnedStackBoundsAnimator.start();
@@ -549,6 +528,27 @@
}
/**
+ * Tries to the move the pinned stack to the given {@param bounds}.
+ */
+ private void movePinnedStack(Rect bounds) {
+ if (!bounds.equals(mPinnedStackBounds)) {
+ mPinnedStackBounds.set(bounds);
+ mMotionHelper.resizeToBounds(mPinnedStackBounds);
+ }
+ }
+
+ /**
+ * Dismisses the pinned stack.
+ */
+ private void dismissPinnedStack() {
+ try {
+ mActivityManager.removeStack(PINNED_STACK_ID);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove PIP", e);
+ }
+ }
+
+ /**
* Updates the movement bounds of the pinned stack.
*/
private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) {
@@ -572,4 +572,237 @@
private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
return PointF.length(r1.left - r2.left, r1.top - r2.top);
}
+
+ /**
+ * Gesture controlling dragging over a target to dismiss the PIP.
+ */
+ private PipTouchGesture mDragToDismissGesture = new PipTouchGesture() {
+ @Override
+ public void onDown(PipTouchState touchState) {
+ if (mEnableDragToDismiss) {
+ // TODO: Consider setting a timer such at after X time, we show the dismiss
+ // target if the user hasn't already dragged some distance
+ mDismissViewController.createDismissTarget();
+ }
+ }
+
+ @Override
+ boolean onMove(PipTouchState touchState) {
+ if (mEnableDragToDismiss && touchState.startedDragging()) {
+ mDismissViewController.showDismissTarget();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onUp(PipTouchState touchState) {
+ if (mEnableDragToDismiss) {
+ try {
+ if (touchState.isDragging()) {
+ Rect dismissBounds = mDismissViewController.getDismissBounds();
+ PointF lastTouch = touchState.getLastTouchPosition();
+ if (dismissBounds.contains((int) lastTouch.x, (int) lastTouch.y)) {
+ animateDismissPinnedStack(dismissBounds);
+ return true;
+ }
+ }
+ } finally {
+ mDismissViewController.destroyDismissTarget();
+ }
+ }
+ return false;
+ }
+ };
+
+ /**** Gestures ****/
+
+ /**
+ * Gesture controlling swiping offscreen to dismiss the PIP.
+ */
+ private PipTouchGesture mSwipeToDismissGesture = new PipTouchGesture() {
+ @Override
+ boolean onMove(PipTouchState touchState) {
+ if (mEnableSwipeToDismiss) {
+ boolean isDraggingOffscreen = isDraggingOffscreen(touchState);
+
+ if (touchState.startedDragging() && isDraggingOffscreen) {
+ // Reset the minimized state once we drag horizontally
+ setMinimizedState(false);
+ }
+
+ if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) {
+ // Move the pinned stack, but ignore the vertical movement
+ float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
+ mTmpBounds.set(mPinnedStackBounds);
+ mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
+ if (!mTmpBounds.equals(mPinnedStackBounds)) {
+ mPinnedStackBounds.set(mTmpBounds);
+ mMotionHelper.resizeToBounds(mPinnedStackBounds);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onUp(PipTouchState touchState) {
+ if (mEnableSwipeToDismiss && touchState.isDragging()) {
+ PointF vel = touchState.getVelocity();
+ PointF downDelta = touchState.getDownTouchDelta();
+ float minFlingVel = mFlingAnimationUtils.getMinVelocityPxPerSecond();
+ float flingVelScale = mEnableMinimizing ? 3f : 2f;
+ if (Math.abs(vel.x) > (flingVelScale * minFlingVel)) {
+ // Determine if this gesture is actually a fling to dismiss
+ if (isFlingToDismiss(vel.x) && Math.abs(downDelta.x) >=
+ (DISMISS_FLING_DISTANCE_FRACTION * mPinnedStackBounds.width())) {
+ flingToDismiss(vel.x);
+ } else {
+ flingToSnapTarget(vel.length(), vel.x, vel.y);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ /**
+ * Gesture controlling dragging the PIP slightly offscreen to minimize it.
+ */
+ private PipTouchGesture mMinimizeGesture = new PipTouchGesture() {
+ @Override
+ boolean onMove(PipTouchState touchState) {
+ if (mEnableMinimizing) {
+ boolean isDraggingOffscreen = isDraggingOffscreen(touchState);
+ if (touchState.startedDragging() && isDraggingOffscreen) {
+ // Reset the minimized state once we drag horizontally
+ setMinimizedState(false);
+ }
+
+ if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) {
+ // Move the pinned stack, but ignore the vertical movement
+ float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x;
+ mTmpBounds.set(mPinnedStackBounds);
+ mTmpBounds.offsetTo((int) left, mPinnedStackBounds.top);
+ if (!mTmpBounds.equals(mPinnedStackBounds)) {
+ mPinnedStackBounds.set(mTmpBounds);
+ mMotionHelper.resizeToBounds(mPinnedStackBounds);
+ }
+ return true;
+ } else if (mIsMinimized && touchState.isDragging()) {
+ // Move the pinned stack, but ignore the horizontal movement
+ PointF lastDelta = touchState.getLastTouchDelta();
+ float top = mPinnedStackBounds.top + lastDelta.y;
+ top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
+ mBoundedPinnedStackBounds.bottom, top));
+ mTmpBounds.set(mPinnedStackBounds);
+ mTmpBounds.offsetTo(mPinnedStackBounds.left, (int) top);
+ movePinnedStack(mTmpBounds);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onUp(PipTouchState touchState) {
+ if (mEnableMinimizing) {
+ if (touchState.isDragging()) {
+ if (isDraggingOffscreen(touchState)) {
+ if (shouldMinimizedPinnedStack()) {
+ setMinimizedState(true);
+ animateToClosestMinimizedTarget();
+ return true;
+ }
+ } else if (mIsMinimized) {
+ PointF vel = touchState.getVelocity();
+ if (vel.length() > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+ flingToMinimizedSnapTarget(vel.y);
+ } else {
+ animateToClosestMinimizedTarget();
+ }
+ return true;
+ }
+ } else if (mIsMinimized) {
+ setMinimizedState(false);
+ animateToClosestSnapTarget();
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ /**
+ * Gesture controlling tapping on the PIP to show an overlay.
+ */
+ private PipTouchGesture mTapThroughGesture = new PipTouchGesture() {
+ @Override
+ boolean onMove(PipTouchState touchState) {
+ if (mEnableTapThrough && touchState.startedDragging()) {
+ mIsTappingThrough = false;
+ mMenuController.hideMenu();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onUp(PipTouchState touchState) {
+ if (mEnableTapThrough && !touchState.isDragging() && !mIsTappingThrough) {
+ mMenuController.showMenu();
+ mIsTappingThrough = true;
+ return true;
+ }
+ return false;
+ }
+ };
+
+ /**
+ * Gesture controlling normal movement of the PIP.
+ */
+ private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
+ @Override
+ boolean onMove(PipTouchState touchState) {
+ if (touchState.startedDragging()) {
+ // For now, once the user has started a drag that the other gestures have not
+ // intercepted, disallow those gestures from intercepting again to drag offscreen
+ touchState.setDisallowDraggingOffscreen();
+ }
+
+ if (touchState.isDragging()) {
+ // Move the pinned stack freely
+ PointF lastDelta = touchState.getLastTouchDelta();
+ float left = mPinnedStackBounds.left + lastDelta.x;
+ float top = mPinnedStackBounds.top + lastDelta.y;
+ if (!DEBUG_ALLOW_OUT_OF_BOUNDS_STACK) {
+ left = Math.max(mBoundedPinnedStackBounds.left, Math.min(
+ mBoundedPinnedStackBounds.right, left));
+ top = Math.max(mBoundedPinnedStackBounds.top, Math.min(
+ mBoundedPinnedStackBounds.bottom, top));
+ }
+ mTmpBounds.set(mPinnedStackBounds);
+ mTmpBounds.offsetTo((int) left, (int) top);
+ movePinnedStack(mTmpBounds);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onUp(PipTouchState touchState) {
+ if (touchState.isDragging()) {
+ PointF vel = mTouchState.getVelocity();
+ float velocity = PointF.length(vel.x, vel.y);
+ if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+ flingToSnapTarget(velocity, vel.x, vel.y);
+ } else {
+ animateToClosestSnapTarget();
+ }
+ } else {
+ expandPinnedStackToFullscreen();
+ }
+ return true;
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
new file mode 100644
index 0000000..17d9864
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip.phone;
+
+import android.app.IActivityManager;
+import android.graphics.PointF;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+/**
+ * This keeps track of the touch state throughout the current touch gesture.
+ */
+public class PipTouchState {
+
+ private ViewConfiguration mViewConfig;
+
+ private VelocityTracker mVelocityTracker;
+ private final PointF mDownTouch = new PointF();
+ private final PointF mDownDelta = new PointF();
+ private final PointF mLastTouch = new PointF();
+ private final PointF mLastDelta = new PointF();
+ private final PointF mVelocity = new PointF();
+ private boolean mIsDragging = false;
+ private boolean mStartedDragging = false;
+ private boolean mAllowDraggingOffscreen = false;
+ private int mActivePointerId;
+
+ public PipTouchState(ViewConfiguration viewConfig) {
+ mViewConfig = viewConfig;
+ }
+
+ /**
+ * Processess a given touch event and updates the state.
+ */
+ public void onTouchEvent(MotionEvent ev) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN: {
+ // Initialize the velocity tracker
+ initOrResetVelocityTracker();
+ mActivePointerId = ev.getPointerId(0);
+ mLastTouch.set(ev.getX(), ev.getY());
+ mDownTouch.set(mLastTouch);
+ mIsDragging = false;
+ mStartedDragging = false;
+ mAllowDraggingOffscreen = true;
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ // Update the velocity tracker
+ mVelocityTracker.addMovement(ev);
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ float x = ev.getX(pointerIndex);
+ float y = ev.getY(pointerIndex);
+ mLastDelta.set(x - mLastTouch.x, y - mLastTouch.y);
+ mDownDelta.set(x - mDownTouch.x, y - mDownTouch.y);
+
+ boolean hasMovedBeyondTap = mDownDelta.length() > mViewConfig.getScaledTouchSlop();
+ if (!mIsDragging) {
+ if (hasMovedBeyondTap) {
+ mIsDragging = true;
+ mStartedDragging = true;
+ }
+ } else {
+ mStartedDragging = false;
+ }
+ mLastTouch.set(x, y);
+ break;
+ }
+ case MotionEvent.ACTION_POINTER_UP: {
+ // Update the velocity tracker
+ mVelocityTracker.addMovement(ev);
+
+ int pointerIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // Select a new active pointer id and reset the movement state
+ final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ mLastTouch.set(ev.getX(newPointerIndex), ev.getY(newPointerIndex));
+ }
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ // Update the velocity tracker
+ mVelocityTracker.addMovement(ev);
+ mVelocityTracker.computeCurrentVelocity(1000,
+ mViewConfig.getScaledMaximumFlingVelocity());
+ mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
+
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ mLastTouch.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+
+ // Fall through to clean up
+ }
+ case MotionEvent.ACTION_CANCEL: {
+ recycleVelocityTracker();
+ break;
+ }
+ }
+ }
+
+ /**
+ * @return the velocity of the active touch pointer at the point it is lifted off the screen.
+ */
+ public PointF getVelocity() {
+ return mVelocity;
+ }
+
+ /**
+ * @return the last touch position of the active pointer.
+ */
+ public PointF getLastTouchPosition() {
+ return mLastTouch;
+ }
+
+ /**
+ * @return the movement delta between the last handled touch event and the previous touch
+ * position.
+ */
+ public PointF getLastTouchDelta() {
+ return mLastDelta;
+ }
+
+ /**
+ * @return the movement delta between the last handled touch event and the down touch
+ * position.
+ */
+ public PointF getDownTouchDelta() {
+ return mDownDelta;
+ }
+
+ /**
+ * @return whether the user has started dragging.
+ */
+ public boolean isDragging() {
+ return mIsDragging;
+ }
+
+ /**
+ * @return whether the user has started dragging just in the last handled touch event.
+ */
+ public boolean startedDragging() {
+ return mStartedDragging;
+ }
+
+ /**
+ * Disallows dragging offscreen for the duration of the current gesture.
+ */
+ public void setDisallowDraggingOffscreen() {
+ mAllowDraggingOffscreen = false;
+ }
+
+ /**
+ * @return whether dragging offscreen is allowed during this gesture.
+ */
+ public boolean allowDraggingOffscreen() {
+ return mAllowDraggingOffscreen;
+ }
+
+ private void initOrResetVelocityTracker() {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ mVelocityTracker.clear();
+ }
+ }
+
+ private void recycleVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 5b93aa2..a622656 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -16,9 +16,9 @@
package com.android.systemui.pip.tv;
+import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -208,7 +208,7 @@
mInitialized = true;
mContext = context;
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
mWindowManager = WindowManagerGlobal.getWindowManagerService();
SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
IntentFilter intentFilter = new IntentFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index e1cd143..dc42adc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -20,7 +20,7 @@
import android.view.View.OnLayoutChangeListener;
import android.widget.TextView;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.PagedTileLayout.PageListener;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSTile.Host.Callback;
@@ -47,7 +47,7 @@
private final ArrayList<View> mTopFiveQs = new ArrayList<>();
private final QuickQSPanel mQuickQsPanel;
private final QSPanel mQsPanel;
- private final QSContainer mQsContainer;
+ private final QS mQs;
private PagedTileLayout mPagedLayout;
@@ -67,12 +67,15 @@
private float mLastPosition;
private QSTileHost mHost;
- public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
- mQsContainer = container;
+ public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel) {
+ mQs = qs;
mQuickQsPanel = quickPanel;
mQsPanel = panel;
mQsPanel.addOnAttachStateChangeListener(this);
- container.addOnLayoutChangeListener(this);
+ qs.getView().addOnLayoutChangeListener(this);
+ if (mQsPanel.isAttachedToWindow()) {
+ onViewAttachedToWindow(null);
+ }
QSTileLayout tileLayout = mQsPanel.getTileLayout();
if (tileLayout instanceof PagedTileLayout) {
mPagedLayout = ((PagedTileLayout) tileLayout);
@@ -102,7 +105,7 @@
@Override
public void onViewAttachedToWindow(View v) {
- TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+ TunerService.get(mQs.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
}
@@ -111,7 +114,7 @@
if (mHost != null) {
mHost.removeCallback(this);
}
- TunerService.get(mQsContainer.getContext()).removeTunable(this);
+ TunerService.get(mQs.getContext()).removeTunable(this);
}
@Override
@@ -124,7 +127,7 @@
} else if (MOVE_FULL_ROWS.equals(key)) {
mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
} else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
- mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQsContainer.getContext());
+ mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQs.getContext());
clearAnimationState();
}
updateAnimators();
@@ -166,13 +169,14 @@
}
final TextView label = ((QSTileView) tileView).getLabel();
final View tileIcon = tileView.getIcon().getIconView();
+ View view = mQs.getView();
if (count < mNumQuickTiles && mAllowFancy) {
// Quick tiles.
QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
lastX = loc1[0];
- getRelativePosition(loc1, quickTileView.getIcon().getIconView(), mQsContainer);
- getRelativePosition(loc2, tileIcon, mQsContainer);
+ getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
+ getRelativePosition(loc2, tileIcon, view);
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
lastXDiff = loc1[0] - lastX;
@@ -198,7 +202,7 @@
// This makes the extra icons seems as if they are coming from positions in the
// quick panel.
loc1[0] += lastXDiff;
- getRelativePosition(loc2, tileIcon, mQsContainer);
+ getRelativePosition(loc2, tileIcon, view);
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f345172..f4da5ec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -16,53 +16,34 @@
package com.android.systemui.qs;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS.HeightListener;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
- *
- * Also manages animations for the QS Header and Panel.
*/
-public class QSContainerImpl extends QSContainer {
- private static final String TAG = "QSContainer";
- private static final boolean DEBUG = false;
+public class QSContainerImpl extends FrameLayout {
private final Point mSizePoint = new Point();
- private final Rect mQsBounds = new Rect();
private int mHeightOverride = -1;
- protected QSPanel mQSPanel;
- private QSDetail mQSDetail;
- protected QuickStatusBarHeader mHeader;
+ protected View mQSPanel;
+ private View mQSDetail;
+ protected View mHeader;
protected float mQsExpansion;
- private boolean mQsExpanded;
- private boolean mHeaderAnimating;
- private boolean mKeyguardShowing;
- private boolean mStackScrollerOverscrolling;
-
- private long mDelay;
- private QSAnimator mQSAnimator;
private QSCustomizer mQSCustomizer;
- private HeightListener mPanelView;
- private boolean mListening;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -71,31 +52,10 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
- mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
- mHeader = (QuickStatusBarHeader) findViewById(R.id.header);
- mQSDetail.setQsPanel(mQSPanel, mHeader);
- mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
- mQSPanel);
+ mQSPanel = findViewById(R.id.quick_settings_panel);
+ mQSDetail = findViewById(R.id.qs_detail);
+ mHeader = findViewById(R.id.header);
mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
- mQSCustomizer.setQsContainer(this);
- }
-
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- super.onRtlPropertiesChanged(layoutDirection);
- mQSAnimator.onRtlChanged();
- }
-
- public void setHost(QSTileHost qsh) {
- mQSPanel.setHost(qsh, mQSCustomizer);
- mHeader.setQSPanel(mQSPanel);
- mQSDetail.setHost(qsh);
- mQSAnimator.setHost(qsh);
- }
-
- public void setPanelView(HeightListener panelView) {
- mPanelView = panelView;
}
@Override
@@ -111,8 +71,8 @@
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- // QSCustomizer is always be the height of the screen, but do this after
- // other measuring to avoid changing the height of the QSContainer.
+ // QSCustomizer will always be the height of the screen, but do this after
+ // other measuring to avoid changing the height of the QS.
getDisplay().getRealSize(mSizePoint);
mQSCustomizer.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
@@ -124,10 +84,6 @@
updateBottom();
}
- public boolean isCustomizing() {
- return mQSCustomizer.isCustomizing();
- }
-
/**
* Overrides the height of this view (post-layout), so that the content is clipped to that
* height and the background is set to that height.
@@ -139,41 +95,7 @@
updateBottom();
}
- @Override
- public void setContainer(ViewGroup container) {
- if (container instanceof NotificationsQuickSettingsContainer) {
- mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
- }
- }
-
- /**
- * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
- * during closing the detail panel, this already returns the smaller height.
- */
- public int getDesiredHeight() {
- if (isCustomizing()) {
- return getHeight();
- }
- if (mQSDetail.isClosingDetail()) {
- int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
- + mQSPanel.getMeasuredHeight();
- return panelHeight + getPaddingBottom();
- } else {
- return getMeasuredHeight();
- }
- }
-
- public void notifyCustomizeChanged() {
- // The customize state changed, so our height changed.
- updateBottom();
- mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
- mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
- // Let the panel know the position changed and it needs to update where notifications
- // and whatnot are.
- mPanelView.onQsHeightChanged();
- }
-
- private void updateBottom() {
+ void updateBottom() {
int height = calculateContainerHeight();
setBottom(getTop() + height);
mQSDetail.setBottom(getTop() + height);
@@ -182,162 +104,12 @@
protected int calculateContainerHeight() {
int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
- : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
- + mHeader.getCollapsedHeight();
+ : (int) (mQsExpansion * (heightOverride - mHeader.getHeight()))
+ + mHeader.getHeight();
}
- private void updateQsState() {
- boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
- mQSPanel.setExpanded(mQsExpanded);
- mQSDetail.setExpanded(mQsExpanded);
- mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
- ? View.VISIBLE
- : View.INVISIBLE);
- mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
- || (mQsExpanded && !mStackScrollerOverscrolling));
- mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
- }
-
- public BaseStatusBarHeader getHeader() {
- return mHeader;
- }
-
- public QSPanel getQsPanel() {
- return mQSPanel;
- }
-
- public QSCustomizer getCustomizer() {
- return mQSCustomizer;
- }
-
- public boolean isShowingDetail() {
- return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
- }
-
- public void setHeaderClickable(boolean clickable) {
- if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
- mHeader.setClickable(clickable);
- }
-
- public void setExpanded(boolean expanded) {
- if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
- mQsExpanded = expanded;
- mQSPanel.setListening(mListening && mQsExpanded);
- updateQsState();
- }
-
- public void setKeyguardShowing(boolean keyguardShowing) {
- if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
- mKeyguardShowing = keyguardShowing;
- mQSAnimator.setOnKeyguard(keyguardShowing);
- updateQsState();
- }
-
- public void setOverscrolling(boolean stackScrollerOverscrolling) {
- if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
- mStackScrollerOverscrolling = stackScrollerOverscrolling;
- updateQsState();
- }
-
- public void setListening(boolean listening) {
- if (DEBUG) Log.d(TAG, "setListening " + listening);
- mListening = listening;
- mHeader.setListening(listening);
- mQSPanel.setListening(mListening && mQsExpanded);
- }
-
- public void setHeaderListening(boolean listening) {
- mHeader.setListening(listening);
- }
-
- public void setQsExpansion(float expansion, float headerTranslation) {
- if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ public void setExpansion(float expansion) {
mQsExpansion = expansion;
- final float translationScaleY = expansion - 1;
- if (!mHeaderAnimating) {
- setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
- : headerTranslation);
- }
- mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
- mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
- mQSDetail.setFullyExpanded(expansion == 1);
- mQSAnimator.setPosition(expansion);
updateBottom();
-
- // Set bounds on the QS panel so it doesn't run over the header.
- mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
- mQsBounds.right = mQSPanel.getWidth();
- mQsBounds.bottom = mQSPanel.getHeight();
- mQSPanel.setClipBounds(mQsBounds);
- }
-
- public void animateHeaderSlidingIn(long delay) {
- if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
- // If the QS is already expanded we don't need to slide in the header as it's already
- // visible.
- if (!mQsExpanded) {
- mHeaderAnimating = true;
- mDelay = delay;
- getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
- }
- }
-
- public void animateHeaderSlidingOut() {
- if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
- mHeaderAnimating = true;
- animate().y(-mHeader.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- animate().setListener(null);
- mHeaderAnimating = false;
- updateQsState();
- }
- })
- .start();
- }
-
- @Override
- public void closeDetail() {
- mQSPanel.closeDetail();
- }
-
- private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
- = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getViewTreeObserver().removeOnPreDrawListener(this);
- animate()
- .translationY(0f)
- .setStartDelay(mDelay)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setListener(mAnimateHeaderSlidingInListener)
- .start();
- setY(-mHeader.getHeight());
- return true;
- }
- };
-
- private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
- = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeaderAnimating = false;
- updateQsState();
- }
- };
-
- public int getQsMinExpansionHeight() {
- return mHeader.getHeight();
- }
-
- @Override
- public void hideImmediately() {
- animate().cancel();
- setY(-mHeader.getHeight());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 2b9320b..5027144 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -35,9 +35,9 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QSContainer.Callback;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.statusbar.phone.QSTileHost;
public class QSDetail extends LinearLayout {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
new file mode 100644
index 0000000..c8f1670
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout.LayoutParams;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+public class QSFragment extends Fragment implements QS {
+ private static final String TAG = "QS";
+ private static final boolean DEBUG = false;
+
+ private final Rect mQsBounds = new Rect();
+ private boolean mQsExpanded;
+ private boolean mHeaderAnimating;
+ private boolean mKeyguardShowing;
+ private boolean mStackScrollerOverscrolling;
+
+ private long mDelay;
+
+ private QSAnimator mQSAnimator;
+ private HeightListener mPanelView;
+ protected QuickStatusBarHeader mHeader;
+ private QSCustomizer mQSCustomizer;
+ protected QSPanel mQSPanel;
+ private QSDetail mQSDetail;
+ private boolean mListening;
+ private QSContainerImpl mContainer;
+ private int mLayoutDirection;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.qs_panel, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mQSPanel = (QSPanel) view.findViewById(R.id.quick_settings_panel);
+ mQSDetail = (QSDetail) view.findViewById(R.id.qs_detail);
+ mHeader = (QuickStatusBarHeader) view.findViewById(R.id.header);
+ mContainer = (QSContainerImpl) view;
+
+ mQSDetail.setQsPanel(mQSPanel, mHeader);
+ mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+ mQSPanel);
+ mQSCustomizer = (QSCustomizer) view.findViewById(R.id.qs_customize);
+ mQSCustomizer.setQs(this);
+ }
+
+ public void setPanelView(HeightListener panelView) {
+ mPanelView = panelView;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (newConfig.getLayoutDirection() != mLayoutDirection) {
+ mLayoutDirection = newConfig.getLayoutDirection();
+ mQSAnimator.onRtlChanged();
+ }
+ }
+
+ @Override
+ public void setContainer(ViewGroup container) {
+ if (container instanceof NotificationsQuickSettingsContainer) {
+ mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
+ }
+ }
+
+ public boolean isCustomizing() {
+ return mQSCustomizer.isCustomizing();
+ }
+
+ public void setHost(QSTileHost qsh) {
+ mQSPanel.setHost(qsh, mQSCustomizer);
+ mHeader.setQSPanel(mQSPanel);
+ mQSDetail.setHost(qsh);
+ mQSAnimator.setHost(qsh);
+ }
+
+ private void updateQsState() {
+ final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
+ || mHeaderAnimating;
+ mQSPanel.setExpanded(mQsExpanded);
+ mQSDetail.setExpanded(mQsExpanded);
+ mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+ ? View.VISIBLE
+ : View.INVISIBLE);
+ mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+ || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ public BaseStatusBarHeader getHeader() {
+ return mHeader;
+ }
+
+ public QSPanel getQsPanel() {
+ return mQSPanel;
+ }
+
+ public QSCustomizer getCustomizer() {
+ return mQSCustomizer;
+ }
+
+ public boolean isShowingDetail() {
+ return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
+ }
+
+ public void setHeaderClickable(boolean clickable) {
+ if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+ mHeader.setClickable(clickable);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+ mQsExpanded = expanded;
+ mQSPanel.setListening(mListening && mQsExpanded);
+ updateQsState();
+ }
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+ mKeyguardShowing = keyguardShowing;
+ mQSAnimator.setOnKeyguard(keyguardShowing);
+ updateQsState();
+ }
+
+ public void setOverscrolling(boolean stackScrollerOverscrolling) {
+ if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+ mStackScrollerOverscrolling = stackScrollerOverscrolling;
+ updateQsState();
+ }
+
+ public void setListening(boolean listening) {
+ if (DEBUG) Log.d(TAG, "setListening " + listening);
+ mListening = listening;
+ mHeader.setListening(listening);
+ mQSPanel.setListening(mListening && mQsExpanded);
+ }
+
+ public void setHeaderListening(boolean listening) {
+ mHeader.setListening(listening);
+ }
+
+ public void setQsExpansion(float expansion, float headerTranslation) {
+ if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ mContainer.setExpansion(expansion);
+ final float translationScaleY = expansion - 1;
+ if (!mHeaderAnimating) {
+ getView().setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+ : headerTranslation);
+ }
+ mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+ mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+ mQSDetail.setFullyExpanded(expansion == 1);
+ mQSAnimator.setPosition(expansion);
+
+ // Set bounds on the QS panel so it doesn't run over the header.
+ mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+ mQsBounds.right = mQSPanel.getWidth();
+ mQsBounds.bottom = mQSPanel.getHeight();
+ mQSPanel.setClipBounds(mQsBounds);
+ }
+
+ public void animateHeaderSlidingIn(long delay) {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+ // If the QS is already expanded we don't need to slide in the header as it's already
+ // visible.
+ if (!mQsExpanded) {
+ mHeaderAnimating = true;
+ mDelay = delay;
+ getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+ }
+ }
+
+ public void animateHeaderSlidingOut() {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+ mHeaderAnimating = true;
+ getView().animate().y(-mHeader.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ getView().animate().setListener(null);
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ })
+ .start();
+ }
+
+ @Override
+ public void closeDetail() {
+ mQSPanel.closeDetail();
+ }
+
+ public void notifyCustomizeChanged() {
+ // The customize state changed, so our height changed.
+ mContainer.updateBottom();
+ mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ // Let the panel know the position changed and it needs to update where notifications
+ // and whatnot are.
+ mPanelView.onQsHeightChanged();
+ }
+
+ /**
+ * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
+ * during closing the detail panel, this already returns the smaller height.
+ */
+ public int getDesiredHeight() {
+ if (mQSCustomizer.isCustomizing()) {
+ return getView().getHeight();
+ }
+ if (mQSDetail.isClosingDetail()) {
+ int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+ + mQSPanel.getMeasuredHeight();
+ return panelHeight + getView().getPaddingBottom();
+ } else {
+ return getView().getMeasuredHeight();
+ }
+ }
+
+ @Override
+ public void setHeightOverride(int desiredHeight) {
+ mContainer.setHeightOverride(desiredHeight);
+ }
+
+ public int getQsMinExpansionHeight() {
+ return mHeader.getHeight();
+ }
+
+ @Override
+ public void hideImmediately() {
+ getView().animate().cancel();
+ getView().setY(-mHeader.getHeight());
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getView().getViewTreeObserver().removeOnPreDrawListener(this);
+ getView().animate()
+ .translationY(0f)
+ .setStartDelay(mDelay)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(mAnimateHeaderSlidingInListener)
+ .start();
+ getView().setY(-mHeader.getHeight());
+ return true;
+ }
+ };
+
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index c699e27..e55ff70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -28,10 +28,10 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile.Host.Callback;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.external.CustomTile;
@@ -60,7 +60,7 @@
protected boolean mExpanded;
protected boolean mListening;
- private QSContainer.Callback mCallback;
+ private QS.Callback mCallback;
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
@@ -171,7 +171,7 @@
return mBrightnessView;
}
- public void setCallback(QSContainer.Callback callback) {
+ public void setCallback(QS.Callback callback) {
mCallback = callback;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39ce324..4341d17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -29,9 +29,9 @@
import android.util.SparseArray;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.qs.external.TileServices;
import com.android.systemui.statusbar.phone.ManagedProfileController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index cf2c16d..9bbead4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -35,9 +35,9 @@
import android.widget.Toolbar.OnMenuItemClickListener;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -69,7 +69,7 @@
private Toolbar mToolbar;
private boolean mCustomizing;
private NotificationsQuickSettingsContainer mNotifQsContainer;
- private QSContainer mQsContainer;
+ private QS mQs;
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
@@ -127,8 +127,8 @@
mNotifQsContainer = notificationsQsContainer;
}
- public void setQsContainer(QSContainer qsContainer) {
- mQsContainer = qsContainer;
+ public void setQs(QS qs) {
+ mQs = qs;
}
public void show(int x, int y) {
@@ -169,7 +169,7 @@
private void setCustomizing(boolean customizing) {
mCustomizing = customizing;
- mQsContainer.notifyCustomizeChanged();
+ mQs.notifyCustomizeChanged();
}
public boolean isCustomizing() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 8d7f6ee..f2c3e61 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -40,7 +40,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.R;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.customize.TileAdapter.Holder;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index dc68112..28530d7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -37,7 +37,7 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 91a0eb0..342df5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -143,6 +143,7 @@
}
public void handleDestroy() {
+ setBindAllowed(false);
mServices.getContext().unregisterReceiver(mUninstallReceiver);
mStateManager.handleDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 6bc94b2..015a4c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -306,6 +306,11 @@
}
}
+ public void destroy() {
+ mServices.values().forEach(service -> service.handleDestroy());
+ mContext.unregisterReceiver(mRequestListeningReceiver);
+ }
+
private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index a980a7f..e57cd58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -26,7 +26,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index d89fbfd3c..fc1c1ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -20,8 +20,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Looper;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@@ -35,12 +33,12 @@
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.BatteryInfo;
import com.android.settingslib.graph.UsageView;
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -80,9 +78,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mBatteryController.addStateChangedCallback(this);
+ mBatteryController.addCallback(this);
} else {
- mBatteryController.removeStateChangedCallback(this);
+ mBatteryController.removeCallback(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 18bde27..f83b279 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -29,10 +29,10 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSTile;
@@ -67,9 +67,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addStateChangedCallback(mCallback);
+ mController.addCallback(mCallback);
} else {
- mController.removeStateChangedCallback(mCallback);
+ mController.removeCallback(mCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 61bad77..8afa91e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -26,9 +26,9 @@
import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 7de883e..1406c9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -26,10 +26,10 @@
import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.SignalTileView;
@@ -68,9 +68,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addSignalCallback(mSignalCallback);
+ mController.addCallback(mSignalCallback);
} else {
- mController.removeSignalCallback(mSignalCallback);
+ mController.removeCallback(mSignalCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5ae7a76..77f063d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -22,7 +22,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.SecureSetting;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index aabafe1..65432dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -19,7 +19,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -44,9 +44,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mDataSaverController.addListener(this);
+ mDataSaverController.addCallback(this);
} else {
- mDataSaverController.remListener(this);
+ mDataSaverController.removeCallback(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ec4ab51..198375d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -33,11 +33,11 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysUIToast;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 0aa723e..5b1638fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -25,7 +25,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -45,13 +45,13 @@
public FlashlightTile(Host host) {
super(host);
mFlashlightController = host.getFlashlightController();
- mFlashlightController.addListener(this);
+ mFlashlightController.addCallback(this);
}
@Override
protected void handleDestroy() {
super.handleDestroy();
- mFlashlightController.removeListener(this);
+ mFlashlightController.removeCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 016c4b7..dcee659 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,8 +16,6 @@
package com.android.systemui.qs.tiles;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserManager;
@@ -29,7 +27,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 2a2cc46..f968816 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -30,7 +30,7 @@
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.qs.QSTile;
import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 5b5ecae..8a9a696 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -23,7 +23,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -58,10 +58,10 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addSettingsChangedCallback(mCallback);
+ mController.addCallback(mCallback);
mKeyguard.addCallback(mCallback);
} else {
- mController.removeSettingsChangedCallback(mCallback);
+ mController.removeCallback(mCallback);
mKeyguard.removeCallback(mCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index c02e5ae..10fde30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -23,7 +23,7 @@
import com.android.internal.app.NightDisplayController;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 499eb50..cec5f15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -24,7 +24,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -61,9 +61,9 @@
public void setListening(boolean listening) {
if (mController == null) return;
if (listening) {
- mController.addRotationLockControllerCallback(mCallback);
+ mController.addCallback(mCallback);
} else {
- mController.removeRotationLockControllerCallback(mCallback);
+ mController.removeCallback(mCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index cd09231c..91d38bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -24,7 +24,7 @@
import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index b5fbfe0..246c23e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -21,8 +21,8 @@
import android.provider.Settings;
import android.util.Pair;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -67,9 +67,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mUserInfoController.addListener(this);
+ mUserInfoController.addCallback(this);
} else {
- mUserInfoController.remListener(this);
+ mUserInfoController.removeCallback(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 27306fc..3876c88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -28,10 +28,10 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSIconView;
@@ -70,9 +70,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addSignalCallback(mSignalCallback);
+ mController.addCallback(mSignalCallback);
} else {
- mController.removeSignalCallback(mSignalCallback);
+ mController.removeCallback(mSignalCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 459e8ec..ce7fbd3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -21,7 +21,7 @@
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.phone.ManagedProfileController;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e203c2f..7655e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -41,7 +41,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index ec99d20..af1823c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -40,7 +40,7 @@
import android.view.WindowManager.LayoutParams;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.keyguard.LatencyTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index b961055..cf75c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -19,7 +19,6 @@
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -117,7 +116,7 @@
public void onClick(View v) {
if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
try {
- ActivityManagerNative.getDefault().startSystemLockTaskMode(taskId);
+ ActivityManager.getService().startSystemLockTaskMode(taskId);
} catch (RemoteException e) {}
}
clearPrompt();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
index 96644b5..e1e654d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java
@@ -15,23 +15,25 @@
*/
package com.android.systemui.recents.grid;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
-import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -59,7 +61,6 @@
import com.android.systemui.recents.views.TaskView;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
@@ -70,11 +71,12 @@
private TaskStack mTaskStack;
private List<Task> mTasks = new ArrayList<>();
- private List<View> mTaskViews = new ArrayList<>();
+ private List<TaskView> mTaskViews = new ArrayList<>();
private FrameLayout mRecentsView;
private TextView mEmptyView;
private View mClearAllButton;
- private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
+ private int mLastDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
+ private int mLastDisplayDensity;
private Rect mDisplayRect = new Rect();
private LayoutInflater mInflater;
private boolean mTouchExplorationEnabled;
@@ -86,11 +88,18 @@
SystemServicesProxy ssp = Recents.getSystemServices();
mInflater = LayoutInflater.from(this);
- mDisplayOrientation = Utilities.getAppConfiguration(this).orientation;
+ Configuration appConfiguration = Utilities.getAppConfiguration(this);
mDisplayRect = ssp.getDisplayRect();
+ mLastDisplayOrientation = appConfiguration.orientation;
+ mLastDisplayDensity = appConfiguration.densityDpi;
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
mRecentsView = (FrameLayout) findViewById(R.id.recents_view);
+ mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container);
mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false);
mClearAllButton = findViewById(R.id.button);
@@ -122,16 +131,29 @@
return (TaskView) mInflater.inflate(R.layout.recents_task_view, mRecentsView, false);
}
- private void clearTaskViews() {
+ private void removeTaskViews() {
for (View taskView : mTaskViews) {
ViewGroup parent = (ViewGroup) taskView.getParent();
if (parent != null) {
parent.removeView(taskView);
}
}
+ }
+
+ private void clearTaskViews() {
+ removeTaskViews();
mTaskViews.clear();
}
+ private TaskView getChildViewForTask(Task task) {
+ for (TaskView tv : mTaskViews) {
+ if (tv.getTask() == task) {
+ return tv;
+ }
+ }
+ return null;
+ }
+
private void updateControlVisibility() {
boolean empty = (mTasks.size() == 0);
mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE);
@@ -160,9 +182,7 @@
loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
loader.loadTasks(this, plan, loadOpts);
- List<Task> stackTasks = mTaskStack.getStackTasks();
- Collections.reverse(stackTasks);
- mTasks = stackTasks;
+ mTasks = mTaskStack.getStackTasks();
updateControlVisibility();
@@ -170,7 +190,8 @@
for (int i = 0; i < mTasks.size(); i++) {
Task task = mTasks.get(i);
TaskView taskView = createView();
- taskView.onTaskBound(task, mTouchExplorationEnabled, mDisplayOrientation, mDisplayRect);
+ taskView.onTaskBound(task, mTouchExplorationEnabled, mLastDisplayOrientation,
+ mDisplayRect);
Recents.getTaskLoader().loadTaskData(task);
taskView.setTouchEnabled(true);
// Show dismiss button right away.
@@ -211,6 +232,22 @@
}
@Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // Notify of the config change.
+ Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this);
+ mDisplayRect = Recents.getSystemServices().getDisplayRect();
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ mRecentsView.requestLayout();
+ int numStackTasks = mTaskStack.getStackTaskCount();
+ EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
+ mLastDisplayOrientation != newDeviceConfiguration.orientation,
+ mLastDisplayDensity != newDeviceConfiguration.densityDpi, numStackTasks > 0));
+ mLastDisplayOrientation = newDeviceConfiguration.orientation;
+ mLastDisplayDensity = newDeviceConfiguration.densityDpi;
+ }
+
+ @Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
int width = mRecentsView.getWidth();
@@ -218,9 +255,13 @@
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */);
+ removeTaskViews();
for (int i = 0; i < rects.size(); i++) {
Rect rect = rects.get(i);
- View taskView = mTaskViews.get(i);
+ // We keep the same ordering in the model as other Recents flavors (older tasks are
+ // first in the stack) so that the logic can be similar, but we reverse the order
+ // when placing views on the screen so that most recent tasks are displayed first.
+ View taskView = mTaskViews.get(rects.size() - 1 - i);
taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
taskView.setTranslationX(rect.left);
taskView.setTranslationY(rect.top);
@@ -235,20 +276,46 @@
startActivity(startMain);
}
+ /** Launches the task that recents was launched from if possible. */
+ boolean launchPreviousTask() {
+ if (mRecentsView != null) {
+ Task task = mTaskStack.getLaunchTarget();
+ if (task != null) {
+ TaskView taskView = getChildViewForTask(task);
+ EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
+ INVALID_STACK_ID, false));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Dismisses recents back to the launch target task. */
+ boolean dismissRecentsToLaunchTargetTaskOrHome() {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isRecentsActivityVisible()) {
+ // If we can launch the task that Recents was launched from, do that, otherwise go home.
+ if (launchPreviousTask()) return true;
+ dismissRecentsToHome();
+ }
+ return false;
+ }
+
/**** EventBus events ****/
public final void onBusEvent(HideRecentsEvent event) {
if (event.triggeredFromAltTab) {
- // Do nothing for now.
+ dismissRecentsToLaunchTargetTaskOrHome();
} else if (event.triggeredFromHomeKey) {
dismissRecentsToHome();
+ } else {
+ // Fall through tap on the background view but not on any of the tasks.
+ dismissRecentsToHome();
}
}
public final void onBusEvent(ToggleRecentsEvent event) {
- // Always go back home for simplicity for now. If recents is entered from another app, this
- // code will eventually need to go back to the original app.
- dismissRecentsToHome();
+ dismissRecentsToLaunchTargetTaskOrHome();
}
public final void onBusEvent(DismissTaskViewEvent event) {
@@ -306,7 +373,19 @@
}
public final void onBusEvent(LaunchNextTaskRequestEvent event) {
- // Always go back home for simplicity for now. Quick switch will be supported soon.
+ if (mTaskStack.getTaskCount() > 0) {
+ Task launchTask = mTaskStack.getNextLaunchTarget();
+ TaskView launchTaskView = getChildViewForTask(launchTask);
+ if (launchTaskView != null) {
+ EventBus.getDefault().send(new LaunchTaskEvent(launchTaskView,
+ launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+ MetricsLogger.action(this, MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+ launchTask.key.getComponent().toString());
+ return;
+ }
+ }
+ // We couldn't find a matching task view, or there are no tasks. Just hide recents back
+ // to home.
EventBus.getDefault().send(new HideRecentsEvent(false, true));
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index ea9714f..2272a72 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -25,7 +25,6 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
@@ -157,7 +156,7 @@
/**
* Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
- * ActivityManagerNative.
+ * ActivityManagerService.
* This simply passes callbacks to listeners through {@link H}.
* */
private android.app.TaskStackListener mTaskStackListener = new android.app.TaskStackListener() {
@@ -207,7 +206,7 @@
private SystemServicesProxy(Context context) {
mAccm = AccessibilityManager.getInstance(context);
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- mIam = ActivityManagerNative.getDefault();
+ mIam = ActivityManager.getService();
mPm = context.getPackageManager();
mIpm = AppGlobals.getPackageManager();
mAssistUtils = new AssistUtils(context);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 745f5a5..178cb9f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -849,6 +849,24 @@
return null;
}
+ /**
+ * Returns the task in stack tasks which should be launched next if Recents are toggled
+ * again, or null if there is no task to be launched.
+ */
+ public Task getNextLaunchTarget() {
+ int taskCount = getTaskCount();
+ if (taskCount == 0) {
+ return null;
+ }
+ int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+ if (launchTaskIndex != -1) {
+ launchTaskIndex = Math.max(0, launchTaskIndex - 1);
+ } else {
+ launchTaskIndex = getTaskCount() - 1;
+ }
+ return getStackTasks().get(launchTaskIndex);
+ }
+
/** Returns the index of this task in this current task stack */
public int indexOfStackTask(Task t) {
return mStackTaskList.indexOf(t);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index febeacb..3c7012a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -43,7 +43,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 936354e..8c94c35 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -47,7 +47,7 @@
import android.widget.ScrollView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -1683,17 +1683,11 @@
return;
}
- int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
- if (launchTaskIndex != -1) {
- launchTaskIndex = Math.max(0, launchTaskIndex - 1);
- } else {
- launchTaskIndex = mStack.getTaskCount() - 1;
- }
- if (launchTaskIndex != -1) {
+ final Task launchTask = mStack.getNextLaunchTarget();
+ if (launchTask != null) {
// Stop all animations
cancelAllTaskViewAnimations();
- final Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
float curScroll = mStackScroller.getStackScroll();
float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
float absScrollDiff = Math.abs(targetScroll - curScroll);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index d44aa84..71f559b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -34,7 +34,7 @@
import android.view.animation.Interpolator;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index e91c9d5..de7def6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -39,7 +39,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 3ed2698..e8039c3 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -33,7 +33,7 @@
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 803fe48..901d47d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -25,7 +25,7 @@
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
/** A dialog that provides controls for adjusting the screen brightness. */
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 15d26f9a..19eefec 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -18,7 +18,6 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -35,7 +34,7 @@
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.settingslib.accessibility.AccessibilityUtils;
import com.android.systemui.R;
@@ -59,7 +58,7 @@
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
- private IActivityManager mActivityManager = ActivityManagerNative.getDefault();
+ private IActivityManager mActivityManager = ActivityManager.getService();
protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE;
protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 4e34bbc..47d2def 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -54,7 +54,7 @@
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index ef32f7e..c245126 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -19,7 +19,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.view.WindowManager.DOCKED_INVALID;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
@@ -72,7 +72,7 @@
mTmpRect5.set(mTempOtherInsetRect);
}
try {
- ActivityManagerNative.getDefault()
+ ActivityManager.getService()
.resizeDockedStack(mTmpRect1,
mTmpRect2.isEmpty() ? null : mTmpRect2,
mTmpRect3.isEmpty() ? null : mTmpRect3,
@@ -88,7 +88,7 @@
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().moveTasksToFullscreenStack(
+ ActivityManager.getService().moveTasksToFullscreenStack(
DOCKED_STACK_ID, false /* onTop */);
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove stack: " + e);
@@ -100,7 +100,7 @@
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().resizeStack(
+ ActivityManager.getService().resizeStack(
DOCKED_STACK_ID, null, true, true, false, -1);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
@@ -124,7 +124,7 @@
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().swapDockedAndFullscreenStack();
+ ActivityManager.getService().swapDockedAndFullscreenStack();
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 23acb1b..19e511cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -20,7 +20,6 @@
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
@@ -87,7 +86,7 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.widget.LockPatternUtils;
@@ -334,7 +333,7 @@
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
try {
- ActivityManagerNative.getDefault().resumeAppSwitches();
+ ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
final boolean isActivity = pendingIntent.isActivity();
@@ -346,7 +345,7 @@
@Override
public boolean onDismiss() {
try {
- ActivityManagerNative.getDefault().resumeAppSwitches();
+ ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
@@ -515,7 +514,7 @@
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
List<ActivityManager.RecentTaskInfo> recentTask = null;
try {
- recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
+ recentTask = ActivityManager.getService().getRecentTasks(1,
ActivityManager.RECENT_WITH_EXCLUDED
| ActivityManager.RECENT_INCLUDE_PROFILES,
mCurrentUserId).getList();
@@ -1321,7 +1320,7 @@
protected void sendCloseSystemWindows(String reason) {
try {
- ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ ActivityManager.getService().closeSystemDialogs(reason);
} catch (RemoteException e) {
}
}
@@ -1820,7 +1819,7 @@
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
- ActivityManagerNative.getDefault().resumeAppSwitches();
+ ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
try {
@@ -1924,7 +1923,7 @@
// won't have permission to immediately start an activity after
// the user switches to home. We know it is safe to do at this
// point, so make sure new activity switches are now allowed.
- ActivityManagerNative.getDefault().resumeAppSwitches();
+ ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
if (intent != null) {
@@ -1938,7 +1937,7 @@
&& mKeyguardManager.isDeviceLocked(userId)) {
boolean canBypass = false;
try {
- canBypass = ActivityManagerNative.getDefault()
+ canBypass = ActivityManager.getService()
.canBypassWorkChallenge(intent);
} catch (RemoteException e) {
}
@@ -2058,7 +2057,7 @@
Intent.EXTRA_INTENT,
callBackPendingIntent.getIntentSender());
try {
- ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
+ ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent);
} catch (RemoteException ex) {
// ignore
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index caf5447..5173176 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -43,7 +43,7 @@
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index f438762..f43fc40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -59,7 +59,7 @@
import com.android.internal.app.AssistUtils;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index b10fb31..bb327ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -43,7 +43,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 74caa53..68d5cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -151,8 +151,8 @@
mBlockEthernet = blockEthernet;
mBlockWifi = blockWifi;
// Re-register to get new callbacks.
- mNC.removeSignalCallback(this);
- mNC.addSignalCallback(this);
+ mNC.removeCallback(this);
+ mNC.addCallback(this);
}
}
@@ -224,7 +224,7 @@
apply();
applyIconTint();
- mNC.addSignalCallback(this);
+ mNC.addCallback(this);
}
@Override
@@ -232,7 +232,7 @@
mMobileSignalGroup.removeAllViews();
TunerService.get(mContext).removeTunable(this);
mSC.removeCallback(this);
- mNC.removeSignalCallback(this);
+ mNC.removeCallback(this);
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
index 4977202..fc39648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -99,7 +99,7 @@
}
@Override
- public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+ public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.add(cb);
// There is no way to know if the phone is plugged in or charging via bluetooth, so pass
@@ -109,7 +109,7 @@
}
@Override
- public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+ public void removeCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.remove(cb);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index baff680..1c8c317 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -30,7 +30,7 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
import java.net.URISyntaxException;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 8a5a8a0..dd5832b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.car;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -256,7 +255,7 @@
private int startActivityWithOptions(Intent intent, Bundle options) {
int result = ActivityManager.START_CANCELED;
try {
- result = ActivityManagerNative.getDefault().startActivityAsUser(null /* caller */,
+ result = ActivityManager.getService().startActivityAsUser(null /* caller */,
mContext.getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index 66030b9..a3e1b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -94,12 +94,12 @@
filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
mContext.registerReceiver(this, filter);
- mController.addStateChangedCallback(this);
+ mController.addCallback(this);
}
public void stopListening() {
mContext.unregisterReceiver(this);
- mController.removeStateChangedCallback(this);
+ mController.removeCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b742479..a011162 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -42,7 +42,7 @@
host.getHotspotController().addCallback(mHotspotCallback);
}
if (!Prefs.getBoolean(context, Key.QS_DATA_SAVER_ADDED, false)) {
- host.getNetworkController().getDataSaverController().addListener(mDataSaverListener);
+ host.getNetworkController().getDataSaverController().addCallback(mDataSaverListener);
}
if (!Prefs.getBoolean(context, Key.QS_INVERT_COLORS_ADDED, false)) {
mColorsSetting = new SecureSetting(mContext, mHandler,
@@ -69,7 +69,10 @@
}
public void destroy() {
- // TODO: Remove any registered listeners.
+ mColorsSetting.setListening(false);
+ mHost.getHotspotController().removeCallback(mHotspotCallback);
+ mHost.getNetworkController().getDataSaverController().removeCallback(mDataSaverListener);
+ mHost.getManagedProfileController().removeCallback(mProfileCallback);
}
private final ManagedProfileController.Callback mProfileCallback =
@@ -105,7 +108,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mHost.getNetworkController().getDataSaverController().remListener(
+ mHost.getNetworkController().getDataSaverController().removeCallback(
mDataSaverListener);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index dfb06d7..89defec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -20,7 +20,6 @@
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -66,7 +65,7 @@
import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -363,7 +362,7 @@
(DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
if (dpm != null && mPhoneStatusBar != null) {
try {
- final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ final int userId = ActivityManager.getService().getCurrentUser().id;
final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
final boolean disabledBecauseKeyguardSecure =
(disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
@@ -487,7 +486,7 @@
o.setRotationAnimationHint(
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
try {
- result = ActivityManagerNative.getDefault().startActivityAsUser(
+ result = ActivityManager.getService().startActivityAsUser(
null, getContext().getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(getContext().getContentResolver()),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index d94def9..e4c778c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -190,9 +190,9 @@
}
mBatteryListening = listening;
if (mBatteryListening) {
- mBatteryController.addStateChangedCallback(this);
+ mBatteryController.addCallback(this);
} else {
- mBatteryController.removeStateChangedCallback(this);
+ mBatteryController.removeCallback(this);
}
}
@@ -214,7 +214,7 @@
}
public void setUserInfoController(UserInfoController userInfoController) {
- userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
+ userInfoController.addCallback(new UserInfoController.OnUserInfoChangedListener() {
@Override
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
mMultiUserAvatar.setImageDrawable(picture);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
index df4566b..dd7f3cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -46,7 +46,7 @@
BatteryController batteryController) {
mIconController = iconController;
mBatteryController = batteryController;
- batteryController.addStateChangedCallback(this);
+ batteryController.addCallback(this);
}
public void setFingerprintUnlockController(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 951b096..1a46815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -24,11 +24,14 @@
import android.os.UserHandle;
import android.os.UserManager;
+import com.android.systemui.statusbar.phone.ManagedProfileController.Callback;
+import com.android.systemui.statusbar.policy.CallbackController;
+
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
-public class ManagedProfileController {
+public class ManagedProfileController implements CallbackController<Callback> {
private final List<Callback> mCallbacks = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index af9454c..4d4f9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -30,7 +30,7 @@
import android.widget.FrameLayout;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserSwitcherController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 0f800bb..228e8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -27,7 +27,7 @@
import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index df167e6..97df237 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,7 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -422,7 +422,7 @@
private boolean inLockTask() {
try {
- return ActivityManagerNative.getDefault().isInLockTaskMode();
+ return ActivityManager.getService().isInLockTaskMode();
} catch (RemoteException e) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index cda0bfe..068631d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
+import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.pm.ResolveInfo;
@@ -34,6 +35,7 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
@@ -42,15 +44,15 @@
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
-import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.AutoReinflateContainer.InflateListener;
import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -70,7 +72,7 @@
ExpandableView.OnHeightChangedListener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
- HeadsUpManager.OnHeadsUpChangedListener, QSContainer.HeightListener {
+ HeadsUpManager.OnHeadsUpChangedListener, QS.HeightListener {
private static final boolean DEBUG = false;
@@ -92,8 +94,8 @@
private KeyguardAffordanceHelper mAfforanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
- protected QSContainer mQsContainer;
- private AutoReinflateContainer mQsAutoReinflateContainer;
+ private QS mQs;
+ private FrameLayout mQsFrame;
private KeyguardStatusView mKeyguardStatusView;
private TextView mClockView;
private View mReserveNotificationSpace;
@@ -236,31 +238,19 @@
mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
mLastOrientation = getResources().getConfiguration().orientation;
- mQsAutoReinflateContainer =
- (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
- mQsAutoReinflateContainer.addInflateListener(new InflateListener() {
- @Override
- public void onInflated(View v) {
- mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
- mQsContainer.setPanelView(NotificationPanelView.this);
- mQsContainer.getHeader().getExpandView()
- .setOnClickListener(NotificationPanelView.this);
+ mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
+ }
- // recompute internal state when qspanel height changes
- mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- final int height = bottom - top;
- final int oldHeight = oldBottom - oldTop;
- if (height != oldHeight) {
- onQsHeightChanged();
- }
- }
- });
- mNotificationStackScroller.setQsContainer(mQsContainer);
- }
- });
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
}
@Override
@@ -288,12 +278,12 @@
int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams();
+ (FrameLayout.LayoutParams) mQsFrame.getLayoutParams();
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mQsAutoReinflateContainer.setLayoutParams(lp);
- mQsContainer.post(mUpdateHeader);
+ mQsFrame.setLayoutParams(lp);
+ mQs.getView().post(mUpdateHeader);
}
lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -314,8 +304,10 @@
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getQsMinExpansionHeight();
- mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
+ if (mQs != null) {
+ mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+ mQsMaxExpansionHeight = mQs.getDesiredHeight();
+ }
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
@@ -337,8 +329,8 @@
// the desired height so when closing the QS detail, it stays smaller after the size change
// animation is finished but the detail view is still being animated away (this animation
// takes longer than the size change animation).
- if (mQsSizeChangeAnimator == null) {
- mQsContainer.setHeightOverride(mQsContainer.getDesiredHeight());
+ if (mQsSizeChangeAnimator == null && mQs != null) {
+ mQs.setHeightOverride(mQs.getDesiredHeight());
}
updateMaxHeadsUpTranslation();
}
@@ -357,7 +349,7 @@
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQsContainer.setHeightOverride(height);
+ mQs.setHeightOverride(height);
}
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -377,7 +369,7 @@
boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
if (mStatusBarState != StatusBarState.KEYGUARD) {
- stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
+ stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight;
mTopPaddingAdjustment = 0;
} else {
mClockPositionAlgorithm.setup(
@@ -490,7 +482,8 @@
public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mQsContainer.setHeaderClickable(qsExpansionEnabled);
+ if (mQs == null) return;
+ mQs.setHeaderClickable(qsExpansionEnabled);
}
@Override
@@ -571,7 +564,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mBlockTouches || mQsContainer.isCustomizing()) {
+ if (mBlockTouches || mQs.isCustomizing()) {
return false;
}
initDownStates(event);
@@ -731,7 +724,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mBlockTouches || mQsContainer.isCustomizing()) {
+ if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
return false;
}
initDownStates(event);
@@ -804,10 +797,10 @@
}
private boolean isInQsArea(float x, float y) {
- return (x >= mQsAutoReinflateContainer.getX()
- && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth())
+ return (x >= mQsFrame.getX()
+ && x <= mQsFrame.getX() + mQsFrame.getWidth())
&& (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
- || y <= mQsContainer.getY() + mQsContainer.getHeight());
+ || y <= mQs.getView().getY() + mQs.getView().getHeight());
}
private boolean isOpenQsEvent(MotionEvent event) {
@@ -962,7 +955,8 @@
private void setOverScrolling(boolean overscrolling) {
mStackScrollerOverscrolling = overscrolling;
- mQsContainer.setOverscrolling(overscrolling);
+ if (mQs == null) return;
+ mQs.setOverscrolling(overscrolling);
}
private void onQsExpansionStarted() {
@@ -1000,24 +994,28 @@
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
- mQsContainer.setKeyguardShowing(mKeyguardShowing);
+ if (mQs != null) {
+ mQs.setKeyguardShowing(mKeyguardShowing);
+ }
if (oldState == StatusBarState.KEYGUARD
&& (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
? 0 : mStatusBar.calculateGoingToFullShadeDelay();
- mQsContainer.animateHeaderSlidingIn(delay);
+ mQs.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mQsContainer.animateHeaderSlidingOut();
+ mQs.animateHeaderSlidingOut();
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
if (keyguardShowing && oldState != mStatusBarState) {
mKeyguardBottomArea.onKeyguardShowingChanged();
- mQsContainer.hideImmediately();
+ if (mQs != null) {
+ mQs.hideImmediately();
+ }
}
}
if (keyguardShowing) {
@@ -1163,7 +1161,6 @@
}
private void updateQsState() {
- mQsContainer.setExpanded(mQsExpanded);
mNotificationStackScroller.setQsExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
@@ -1176,6 +1173,8 @@
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
}
+ if (mQs == null) return;
+ mQs.setExpanded(mQsExpanded);
}
private void setQsExpansion(float height) {
@@ -1222,11 +1221,12 @@
}
protected void updateQsExpansion() {
- mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
+ if (mQs == null) return;
+ mQs.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
}
private String getKeyguardOrLockScreenString() {
- if (mQsContainer.isCustomizing()) {
+ if (mQs != null && mQs.isCustomizing()) {
return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
} else if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1357,9 +1357,9 @@
if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
- View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
- boolean onHeader = x >= mQsAutoReinflateContainer.getX()
- && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
+ View header = mKeyguardShowing ? mKeyguardStatusBar : mQs.getHeader();
+ final boolean onHeader = x >= mQsFrame.getX()
+ && x <= mQsFrame.getX() + mQsFrame.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -1621,7 +1621,8 @@
}
// Since there are QS tiles in the header now, we need to make sure we start listening
// immediately so they can be up to date.
- mQsContainer.setHeaderListening(true);
+ if (mQs == null) return;
+ mQs.setHeaderListening(true);
}
@Override
@@ -1659,8 +1660,9 @@
}
private void setListening(boolean listening) {
- mQsContainer.setListening(listening);
mKeyguardStatusBar.setListening(listening);
+ if (mQs == null) return;
+ mQs.setListening(listening);
}
@Override
@@ -1748,7 +1750,7 @@
}
public void onQsHeightChanged() {
- mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
+ mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
requestScrollerTopPaddingUpdate(false /* animate */);
@@ -2018,11 +2020,11 @@
}
public boolean isQsDetailShowing() {
- return mQsContainer.isShowingDetail();
+ return mQs.isShowingDetail();
}
public void closeQsDetail() {
- mQsContainer.closeDetail();
+ mQs.closeDetail();
}
@Override
@@ -2110,7 +2112,7 @@
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mQsContainer.getHeader().updateEverything();
+ mQs.getHeader().updateEverything();
}
};
@@ -2257,7 +2259,7 @@
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mQsAutoReinflateContainer.setTranslationX(translation);
+ mQsFrame.setTranslationX(translation);
}
protected void updateExpandedHeight(float expandedHeight) {
@@ -2355,4 +2357,38 @@
public void setGroupManager(NotificationGroupManager groupManager) {
mGroupManager = groupManager;
}
+
+ private final FragmentListener mFragmentListener = new FragmentListener() {
+ @Override
+ public void onFragmentViewCreated(String tag, Fragment fragment) {
+ mQs = (QS) fragment;
+ mQs.setPanelView(NotificationPanelView.this);
+ mQs.getHeader().getExpandView().setOnClickListener(NotificationPanelView.this);
+ mQs.setHeaderClickable(mQsExpansionEnabled);
+ mQs.setKeyguardShowing(mKeyguardShowing);
+ mQs.setOverscrolling(mStackScrollerOverscrolling);
+
+ // recompute internal state when qspanel height changes
+ mQs.getView().addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ final int height = bottom - top;
+ final int oldHeight = oldBottom - oldTop;
+ if (height != oldHeight) {
+ onQsHeightChanged();
+ }
+ });
+ mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
+ updateQsExpansion();
+ }
+
+ @Override
+ public void onFragmentViewDestroyed(String tag, Fragment fragment) {
+ // Manual handling of fragment lifecycle is only required because this bridges
+ // non-fragment and fragment code. Once we are using a fragment for the notification
+ // panel, mQs will not need to be null cause it will be tied to the same lifecycle.
+ if (fragment == mQs) {
+ mQs = null;
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 8b1fcd6..c85584e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.app.Fragment;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
@@ -25,18 +26,17 @@
import android.view.WindowInsets;
import android.widget.FrameLayout;
-import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.plugins.qs.QS;
/**
* The container with notification stack scroller and quick settings inside.
*/
public class NotificationsQuickSettingsContainer extends FrameLayout
- implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener {
+ implements ViewStub.OnInflateListener, FragmentHostManager.FragmentListener {
-
- private AutoReinflateContainer mQsContainer;
+ private FrameLayout mQsFrame;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
@@ -54,8 +54,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
- mQsContainer.addInflateListener(this);
+ mQsFrame = (FrameLayout) findViewById(R.id.qs_frame);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
@@ -65,9 +64,21 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ FragmentHostManager.get(this).addTagListener(QS.TAG, this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- reloadWidth(mQsContainer);
+ reloadWidth(mQsFrame);
reloadWidth(mStackScroller);
}
@@ -91,11 +102,11 @@
boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
final boolean qsBottom = mQsExpanded && !mCustomizerAnimating;
- View stackQsTop = qsBottom ? mStackScroller : mQsContainer;
- View stackQsBottom = !qsBottom ? mStackScroller : mQsContainer;
+ View stackQsTop = qsBottom ? mStackScroller : mQsFrame;
+ View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
- if (child == mQsContainer) {
+ if (child == mQsFrame) {
return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
: statusBarVisible ? mKeyguardStatusBar
: userSwitcherVisible ? mUserSwitcher
@@ -129,8 +140,8 @@
}
@Override
- public void onInflated(View v) {
- QSContainer container = (QSContainer) v;
+ public void onFragmentViewCreated(String tag, Fragment fragment) {
+ QS container = (QS) fragment;
container.setContainer(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index c33d91a..c4fb21e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -34,7 +34,6 @@
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
@@ -90,7 +89,6 @@
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
@@ -118,7 +116,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -126,8 +124,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.AutoReinflateContainer.InflateListener;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogConstants;
@@ -141,11 +137,13 @@
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.PluginFragmentListener;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
-import com.android.systemui.plugins.qs.QSContainer;
-import com.android.systemui.qs.QSContainerImpl;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
@@ -561,6 +559,7 @@
private int mLastCameraLaunchSource;
private PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
+ private long[] mCameraLaunchGestureVibePattern;
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
@@ -874,7 +873,7 @@
mLocationController = new LocationControllerImpl(mContext,
mHandlerThread.getLooper()); // will post a notification
mBatteryController = createBatteryController();
- mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
+ mBatteryController.addCallback(new BatteryStateChangeCallback() {
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mHandler.post(mCheckBarModes);
@@ -922,9 +921,11 @@
}
// Set up the quick settings tile panel
- AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
- R.id.qs_auto_reinflate_container);
+ View container = mStatusBarWindow.findViewById(R.id.qs_frame);
if (container != null) {
+ FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
+ new PluginFragmentListener(container, QS.TAG, R.id.qs_frame, QSFragment.class, QS.class)
+ .startListening(QS.ACTION, QS.VERSION);
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
mNetworkController, mZenModeController, mHotspotController,
@@ -933,21 +934,17 @@
mSecurityController, mBatteryController, mIconController,
mNextAlarmController);
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
- container.addInflateListener(new InflateListener() {
- @Override
- public void onInflated(View v) {
- QSContainer qsContainer = (QSContainer) v.findViewById(
- R.id.quick_settings_container);
- if (qsContainer instanceof QSContainerImpl) {
- ((QSContainerImpl) qsContainer).setHost(qsh);
- mQSPanel = ((QSContainerImpl) qsContainer).getQsPanel();
- mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
- mKeyguardStatusBar.setQSPanel(mQSPanel);
- }
- mHeader = qsContainer.getHeader();
- initSignalCluster(mHeader);
- mHeader.setActivityStarter(PhoneStatusBar.this);
+ fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
+ QS qs = (QS) f;
+ if (qs instanceof QSFragment) {
+ ((QSFragment) qs).setHost(qsh);
+ mQSPanel = ((QSFragment) qs).getQsPanel();
+ mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+ mKeyguardStatusBar.setQSPanel(mQSPanel);
}
+ mHeader = qs.getHeader();
+ initSignalCluster(mHeader);
+ mHeader.setActivityStarter(PhoneStatusBar.this);
});
}
@@ -996,6 +993,12 @@
mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"GestureWakeLock");
mVibrator = mContext.getSystemService(Vibrator.class);
+ int[] pattern = mContext.getResources().getIntArray(
+ R.array.config_cameraLaunchGestureVibePattern);
+ mCameraLaunchGestureVibePattern = new long[pattern.length];
+ for (int i = 0; i < pattern.length; i++) {
+ mCameraLaunchGestureVibePattern[i] = pattern[i];
+ }
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -1030,7 +1033,7 @@
if (emergencyViewStub != null) {
((ViewStub) emergencyViewStub).inflate();
}
- mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
+ mNetworkController.addCallback(new NetworkController.SignalCallback() {
@Override
public void setIsAirplaneMode(NetworkController.IconState icon) {
recomputeDisableFlags(true /* animate */);
@@ -1649,9 +1652,9 @@
newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
- sbn.getOpPkg(),
+ sbn.getOpPkg(), sbn.getNotificationChannel(),
sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
- 0, newNotification, sbn.getUser(), sbn.getPostTime());
+ newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
updateNotification(newSbn, null);
mKeysKeptForRemoteInput.add(entry.key);
@@ -3512,7 +3515,7 @@
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
}
try {
- result = ActivityManagerNative.getDefault().startActivityAsUser(
+ result = ActivityManager.getService().startActivityAsUser(
null, mContext.getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
@@ -3552,8 +3555,14 @@
AsyncTask.execute(runnable);
}
if (dismissShade) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
- true /* delayed*/);
+ if (mExpandedVisible) {
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+ true /* delayed*/);
+ } else {
+
+ // Do it after DismissAction has been processed to conserve the needed ordering.
+ mHandler.post(this::runPostCollapseRunnables);
+ }
}
return deferred;
}, cancelAction, afterKeyguardGone);
@@ -3631,12 +3640,10 @@
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
- public void dismissKeyguard() {
- mStatusBarKeyguardViewManager.dismiss();
- }
-
private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone) {
+ afterKeyguardGone |= mStatusBarKeyguardViewManager.isShowing()
+ && mStatusBarKeyguardViewManager.isOccluded();
if (mStatusBarKeyguardViewManager.isShowing()) {
mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
afterKeyguardGone);
@@ -3974,9 +3981,9 @@
(SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
final SignalClusterView signalClusterQs =
(SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
- mNetworkController.removeSignalCallback(signalCluster);
- mNetworkController.removeSignalCallback(signalClusterKeyguard);
- mNetworkController.removeSignalCallback(signalClusterQs);
+ mNetworkController.removeCallback(signalCluster);
+ mNetworkController.removeCallback(signalClusterKeyguard);
+ mNetworkController.removeCallback(signalClusterQs);
if (mQSPanel != null && mQSPanel.getHost() != null) {
mQSPanel.getHost().destroy();
}
@@ -4249,7 +4256,7 @@
}
}, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
}
- } else {
+ } else if (!mNotificationPanel.isCollapsing()) {
instantCollapseNotificationPanel();
}
updateKeyguardState(staying, false /* fromShadeLocked */);
@@ -4876,7 +4883,7 @@
private void vibrateForCameraGesture() {
// Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
- mVibrator.vibrate(new long[]{0, 400}, -1 /* repeat */);
+ mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
}
public void onScreenTurnedOn() {
@@ -4889,7 +4896,7 @@
*/
private boolean handleLongPressBack() {
try {
- IActivityManager activityManager = ActivityManagerNative.getDefault();
+ IActivityManager activityManager = ActivityManager.getService();
if (activityManager.isInLockTaskMode()) {
activityManager.stopSystemLockTaskMode();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 7187ec2..9ee1e8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
import android.app.SynchronousUserSwitchObserver;
@@ -47,7 +46,6 @@
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -110,7 +108,7 @@
mCast = cast;
mHotspot = hotspot;
mBluetooth = bluetooth;
- mBluetooth.addStateChangedCallback(this);
+ mBluetooth.addCallback(this);
mNextAlarm = nextAlarm;
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mUserInfoController = userInfoController;
@@ -131,7 +129,7 @@
mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
- mRotationLockController.addRotationLockControllerCallback(this);
+ mRotationLockController.addCallback(this);
// listen for broadcasts
IntentFilter filter = new IntentFilter();
@@ -147,7 +145,7 @@
// listen for user / profile change.
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener, TAG);
+ ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
} catch (RemoteException e) {
// Ignore
}
@@ -162,7 +160,7 @@
// Alarm clock
mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
mIconController.setIconVisibility(mSlotAlarmClock, false);
- mNextAlarm.addStateChangedCallback(mNextAlarmCallback);
+ mNextAlarm.addCallback(mNextAlarmCallback);
// zen
mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
@@ -193,7 +191,7 @@
mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
context.getString(R.string.accessibility_data_saver_on));
mIconController.setIconVisibility(mSlotDataSaver, false);
- mDataSaver.addListener(this);
+ mDataSaver.addCallback(this);
}
public void setStatusBarKeyguardViewManager(
@@ -381,7 +379,7 @@
UserInfo user = null;
if (userId == UserHandle.USER_CURRENT) {
try {
- user = ActivityManagerNative.getDefault().getCurrentUser();
+ user = ActivityManager.getService().getCurrentUser();
} catch (RemoteException e) {
// Ignore
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index da698d8..fc15477e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -113,6 +113,7 @@
private final AutoTileManager mAutoTiles;
private final ManagedProfileController mProfileController;
private final NextAlarmController mNextAlarmController;
+ private final HandlerThread mHandlerThread;
private View mHeader;
private int mCurrentUser;
@@ -144,10 +145,10 @@
mNextAlarmController = nextAlarmController;
mProfileController = new ManagedProfileController(this);
- final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
+ mHandlerThread = new HandlerThread(QSTileHost.class.getSimpleName(),
Process.THREAD_PRIORITY_BACKGROUND);
- ht.start();
- mLooper = ht.getLooper();
+ mHandlerThread.start();
+ mLooper = mHandlerThread.getLooper();
mServices = new TileServices(this, mLooper);
@@ -169,8 +170,11 @@
}
public void destroy() {
+ mHandlerThread.quitSafely();
+ mTiles.values().forEach(tile -> tile.destroy());
mAutoTiles.destroy();
TunerService.get(mContext).removeTunable(this);
+ mServices.destroy();
}
@Override
@@ -321,12 +325,11 @@
final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
int currentUser = ActivityManager.getCurrentUser();
if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
- for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
- if (!tileSpecs.contains(tile.getKey())) {
- if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
- tile.getValue().destroy();
- }
- }
+ mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(
+ tile -> {
+ if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
+ tile.getValue().destroy();
+ });
final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
for (String tileSpec : tileSpecs) {
QSTile<?> tile = mTiles.get(tileSpec);
@@ -342,9 +345,13 @@
if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
try {
tile = createTile(tileSpec);
- if (tile != null && tile.isAvailable()) {
- tile.setTileSpec(tileSpec);
- newTiles.put(tileSpec, tile);
+ if (tile != null) {
+ if (tile.isAvailable()) {
+ tile.setTileSpec(tileSpec);
+ newTiles.put(tileSpec, tile);
+ } else {
+ tile.destroy();
+ }
}
} catch (Throwable t) {
Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index a8b0122..28aed87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -33,14 +33,14 @@
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
-import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
import com.android.systemui.qs.QSPanel;
-import com.android.systemui.plugins.qs.QSContainer.Callback;
+import com.android.systemui.plugins.qs.QS.Callback;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.TouchAnimator;
import com.android.systemui.qs.TouchAnimator.Builder;
@@ -238,7 +238,7 @@
@Override
protected void onDetachedFromWindow() {
setListening(false);
- mHost.getUserInfoController().remListener(this);
+ mHost.getUserInfoController().removeCallback(this);
mHost.getNetworkController().removeEmergencyListener(this);
super.onDetachedFromWindow();
}
@@ -290,9 +290,9 @@
private void updateListeners() {
if (mListening) {
- mNextAlarmController.addStateChangedCallback(this);
+ mNextAlarmController.addCallback(this);
} else {
- mNextAlarmController.removeStateChangedCallback(this);
+ mNextAlarmController.removeCallback(this);
}
}
@@ -368,7 +368,7 @@
}
public void setUserInfoController(UserInfoController userInfoController) {
- userInfoController.addListener(this);
+ userInfoController.addCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f5c5e56..69decd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -155,8 +155,8 @@
if (!afterKeyguardGone) {
mBouncer.showWithDismissAction(r, cancelAction);
} else {
- mBouncer.show(false /* resetSecuritySelection */);
mAfterKeyguardGoneAction = r;
+ mBouncer.show(false /* resetSecuritySelection */);
}
}
updateStates();
@@ -235,10 +235,6 @@
mDeviceWillWakeUp = !mDeviceInteractive;
}
- public void verifyUnlock() {
- dismiss();
- }
-
public void setNeedsInput(boolean needsInput) {
mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
}
@@ -333,6 +329,7 @@
}
});
} else {
+ executeAfterKeyguardGoneAction();
if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
mFingerprintUnlockController.startKeyguardFadingAway();
mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
@@ -372,7 +369,6 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide(true /* destroyView */);
mViewMediatorCallback.keyguardGone();
- executeAfterKeyguardGoneAction();
updateStates();
}
}
@@ -423,6 +419,10 @@
/**
* Dismisses the keyguard by going to the next screen or making it gone.
*/
+ public void dismissAndCollapse() {
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
+ }
+
public void dismiss() {
showBouncer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 4a2d5dc..995f4dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.phone;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -64,7 +64,7 @@
public StatusBarWindowManager(Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mScreenBrightnessDoze = mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 559436b..19dcf03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.policy;
import com.android.systemui.DemoMode;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public interface BatteryController extends DemoMode {
+public interface BatteryController extends DemoMode,
+ CallbackController<BatteryStateChangeCallback> {
/**
* Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}.
*/
@@ -37,9 +39,6 @@
*/
boolean isPowerSave();
- void addStateChangedCallback(BatteryStateChangeCallback cb);
- void removeStateChangedCallback(BatteryStateChangeCallback cb);
-
/**
* A listener that will be notified whenever a change in battery level or power save mode
* has occurred.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 6726c92..fc86ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -89,7 +89,7 @@
}
@Override
- public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+ public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
synchronized (mChangeCallbacks) {
mChangeCallbacks.add(cb);
}
@@ -99,7 +99,7 @@
}
@Override
- public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
+ public void removeCallback(BatteryController.BatteryStateChangeCallback cb) {
synchronized (mChangeCallbacks) {
mChangeCallbacks.remove(cb);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 08675c4..4c1c378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -17,13 +17,11 @@
package com.android.systemui.statusbar.policy;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.statusbar.policy.BluetoothController.Callback;
import java.util.Collection;
-public interface BluetoothController {
- void addStateChangedCallback(Callback callback);
- void removeStateChangedCallback(Callback callback);
-
+public interface BluetoothController extends CallbackController<Callback> {
boolean isBluetoothSupported();
boolean isBluetoothEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 4f880b44..15c4afe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -105,13 +105,13 @@
}
@Override
- public void addStateChangedCallback(Callback cb) {
+ public void addCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
@Override
- public void removeStateChangedCallback(Callback cb) {
+ public void removeCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
new file mode 100644
index 0000000..9042ca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+public interface CallbackController<T> {
+ void addCallback(T listener);
+ void removeCallback(T listener);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index 7713e57..6988af7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
+import com.android.systemui.statusbar.policy.CastController.Callback;
+
import java.util.Set;
-public interface CastController {
- void addCallback(Callback callback);
- void removeCallback(Callback callback);
+public interface CastController extends CallbackController<Callback> {
void setDiscovering(boolean request);
void setCurrentUserId(int currentUserId);
Set<CastDevice> getCastDevices();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
index 0fc71d3..e5f1e68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
@@ -21,9 +21,11 @@
import android.os.Looper;
import android.os.RemoteException;
+import com.android.systemui.statusbar.policy.DataSaverController.Listener;
+
import java.util.ArrayList;
-public class DataSaverController {
+public class DataSaverController implements CallbackController<Listener> {
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ArrayList<Listener> mListeners = new ArrayList<>();
@@ -41,7 +43,7 @@
}
}
- public void addListener(Listener listener) {
+ public void addCallback(Listener listener) {
synchronized (mListeners) {
mListeners.add(listener);
if (mListeners.size() == 1) {
@@ -51,7 +53,7 @@
listener.onDataSaverChanged(isDataSaverEnabled());
}
- public void remListener(Listener listener) {
+ public void removeCallback(Listener listener) {
synchronized (mListeners) {
mListeners.remove(listener);
if (mListeners.size() == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 4e9fc76..0f77b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -27,6 +27,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -35,7 +37,7 @@
/**
* Manages the flashlight.
*/
-public class FlashlightController {
+public class FlashlightController implements CallbackController<FlashlightListener> {
private static final String TAG = "FlashlightController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -112,7 +114,7 @@
return mTorchAvailable;
}
- public void addListener(FlashlightListener l) {
+ public void addCallback(FlashlightListener l) {
synchronized (mListeners) {
if (mCameraId == null) {
tryInitCamera();
@@ -122,7 +124,7 @@
}
}
- public void removeListener(FlashlightListener l) {
+ public void removeCallback(FlashlightListener l) {
synchronized (mListeners) {
cleanUpListenersLocked(l);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 4622ea4..daf9d6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -16,9 +16,9 @@
package com.android.systemui.statusbar.policy;
-public interface HotspotController {
- void addCallback(Callback callback);
- void removeCallback(Callback callback);
+import com.android.systemui.statusbar.policy.HotspotController.Callback;
+
+public interface HotspotController extends CallbackController<Callback> {
boolean isHotspotEnabled();
void setHotspotEnabled(boolean enabled);
boolean isHotspotSupported();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 44816f9..fafbdd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -24,10 +24,12 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
import java.util.ArrayList;
-public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback {
+public class KeyguardMonitor extends KeyguardUpdateMonitorCallback
+ implements CallbackController<Callback> {
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..9a5f1b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
-public interface LocationController {
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+public interface LocationController extends CallbackController<LocationSettingsChangeCallback> {
boolean isLocationEnabled();
boolean setLocationEnabled(boolean enabled);
- void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
- void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 8d84be4..cc61605 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -82,12 +82,12 @@
/**
* Add a callback to listen for changes in location settings.
*/
- public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+ public void addCallback(LocationSettingsChangeCallback cb) {
mSettingsChangeCallbacks.add(cb);
mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
}
- public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+ public void removeCallback(LocationSettingsChangeCallback cb) {
mSettingsChangeCallbacks.remove(cb);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 5f1b871..082fe82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -21,14 +21,15 @@
import android.telephony.SubscriptionInfo;
import com.android.settingslib.net.DataUsageController;
import com.android.settingslib.wifi.AccessPoint;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.util.List;
-public interface NetworkController {
+public interface NetworkController extends CallbackController<SignalCallback> {
boolean hasMobileDataFeature();
- void addSignalCallback(SignalCallback cb);
- void removeSignalCallback(SignalCallback cb);
+ void addCallback(SignalCallback cb);
+ void removeCallback(SignalCallback cb);
void setWifiEnabled(boolean enabled);
void onUserSwitched(int newUserId);
AccessPointController getAccessPointController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 37e6a2a..1a9756f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -322,7 +322,7 @@
mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
}
- public void addSignalCallback(SignalCallback cb) {
+ public void addCallback(SignalCallback cb) {
cb.setSubs(mCurrentSubscriptions);
cb.setIsAirplaneMode(new IconState(mAirplaneMode,
TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
@@ -336,7 +336,7 @@
}
@Override
- public void removeSignalCallback(SignalCallback cb) {
+ public void removeCallback(SignalCallback cb) {
mCallbackHandler.setListening(cb, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
index 787acc5..28935bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
@@ -23,11 +23,14 @@
import android.content.IntentFilter;
import android.os.UserHandle;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-public class NextAlarmController extends BroadcastReceiver {
+public class NextAlarmController extends BroadcastReceiver
+ implements CallbackController<NextAlarmChangeCallback> {
private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
@@ -48,12 +51,12 @@
pw.print(" mNextAlarm="); pw.println(mNextAlarm);
}
- public void addStateChangedCallback(NextAlarmChangeCallback cb) {
+ public void addCallback(NextAlarmChangeCallback cb) {
mChangeCallbacks.add(cb);
cb.onNextAlarmChanged(mNextAlarm);
}
- public void removeStateChangedCallback(NextAlarmChangeCallback cb) {
+ public void removeCallback(NextAlarmChangeCallback cb) {
mChangeCallbacks.remove(cb);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7b1f707..44ec283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -50,7 +50,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 93c4691..722874b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -16,13 +16,14 @@
package com.android.systemui.statusbar.policy;
-public interface RotationLockController extends Listenable {
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+public interface RotationLockController extends Listenable,
+ CallbackController<RotationLockControllerCallback> {
int getRotationLockOrientation();
boolean isRotationLockAffordanceVisible();
boolean isRotationLocked();
void setRotationLocked(boolean locked);
- void addRotationLockControllerCallback(RotationLockControllerCallback callback);
- void removeRotationLockControllerCallback(RotationLockControllerCallback callback);
public interface RotationLockControllerCallback {
void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index c3bcd94..4f96496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -42,12 +42,12 @@
setListening(true);
}
- public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+ public void addCallback(RotationLockControllerCallback callback) {
mCallbacks.add(callback);
notifyChanged(callback);
}
- public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
+ public void removeCallback(RotationLockControllerCallback callback) {
mCallbacks.remove(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 014afae..43ced48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -15,7 +15,9 @@
*/
package com.android.systemui.statusbar.policy;
-public interface SecurityController {
+import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
+
+public interface SecurityController extends CallbackController<SecurityControllerCallback> {
/** Whether the device has device owner, even if not on this user. */
boolean isDeviceManaged();
boolean hasProfileOwner();
@@ -29,9 +31,6 @@
String getProfileVpnName();
void onUserSwitched(int newUserId);
- void addCallback(SecurityControllerCallback callback);
- void removeCallback(SecurityControllerCallback callback);
-
public interface SecurityControllerCallback {
void onStateChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index 4a6e215..c09747b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -38,10 +37,11 @@
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
import java.util.ArrayList;
-public final class UserInfoController {
+public class UserInfoController implements CallbackController<OnUserInfoChangedListener> {
private static final String TAG = "UserInfoController";
@@ -67,12 +67,12 @@
null, null);
}
- public void addListener(OnUserInfoChangedListener callback) {
+ public void addCallback(OnUserInfoChangedListener callback) {
mCallbacks.add(callback);
callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount);
}
- public void remListener(OnUserInfoChangedListener callback) {
+ public void removeCallback(OnUserInfoChangedListener callback) {
mCallbacks.remove(callback);
}
@@ -93,7 +93,7 @@
if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
try {
- final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+ final int currentUser = ActivityManager.getService().getCurrentUser().id;
final int changedUser =
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
if (changedUser == currentUser) {
@@ -118,7 +118,7 @@
Context currentUserContext;
UserInfo userInfo;
try {
- userInfo = ActivityManagerNative.getDefault().getCurrentUser();
+ userInfo = ActivityManager.getService().getCurrentUser();
currentUserContext = mContext.createPackageContextAsUser("android", 0,
new UserHandle(userInfo.id));
} catch (PackageManager.NameNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 30d1c54..bb4b91e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -19,7 +19,6 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
@@ -48,16 +47,17 @@
import android.view.ViewGroup;
import android.widget.BaseAdapter;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUISecondaryUserService;
-import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
+import com.android.systemui.plugins.qs.QS.DetailAdapter;
import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QS.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.io.FileDescriptor;
@@ -411,7 +411,7 @@
protected void switchToUserId(int id) {
try {
pauseRefreshUsers();
- ActivityManagerNative.getDefault().switchUser(id);
+ ActivityManager.getService().switchUser(id);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't switch user.", e);
}
@@ -640,28 +640,43 @@
refreshUsers(UserHandle.USER_ALL);
}
+ @VisibleForTesting
+ public void addAdapter(WeakReference<BaseUserAdapter> adapter) {
+ mAdapters.add(adapter);
+ }
+
+ @VisibleForTesting
+ public KeyguardMonitor getKeyguardMonitor() {
+ return mKeyguardMonitor;
+ }
+
+ @VisibleForTesting
+ public ArrayList<UserRecord> getUsers() {
+ return mUsers;
+ }
+
public static abstract class BaseUserAdapter extends BaseAdapter {
final UserSwitcherController mController;
protected BaseUserAdapter(UserSwitcherController controller) {
mController = controller;
- controller.mAdapters.add(new WeakReference<>(this));
+ controller.addAdapter(new WeakReference<>(this));
}
@Override
public int getCount() {
- boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
- && mController.mKeyguardMonitor.isSecure()
- && !mController.mKeyguardMonitor.canSkipBouncer();
+ boolean secureKeyguardShowing = mController.getKeyguardMonitor().isShowing()
+ && mController.getKeyguardMonitor().isSecure()
+ && !mController.getKeyguardMonitor().canSkipBouncer();
if (!secureKeyguardShowing) {
- return mController.mUsers.size();
+ return mController.getUsers().size();
}
// The lock screen is secure and showing. Filter out restricted records.
- final int N = mController.mUsers.size();
+ final int N = mController.getUsers().size();
int count = 0;
for (int i = 0; i < N; i++) {
- if (mController.mUsers.get(i).isRestricted) {
+ if (mController.getUsers().get(i).isRestricted) {
break;
} else {
count++;
@@ -672,7 +687,7 @@
@Override
public UserRecord getItem(int position) {
- return mController.mUsers.get(position);
+ return mController.getUsers().get(position);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 0e91b0b..bcdb62d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -22,9 +22,9 @@
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
-public interface ZenModeController {
- void addCallback(Callback callback);
- void removeCallback(Callback callback);
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+
+public interface ZenModeController extends CallbackController<Callback> {
void setZen(int zen, Uri conditionId, String reason);
int getZen();
ZenRule getManualRule();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index da58d9e..72a0e59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -57,7 +57,7 @@
import android.widget.ScrollView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index 6e08139..9998283 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -21,7 +21,7 @@
import android.util.ArraySet;
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a3197c..0a962f1 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -31,7 +31,7 @@
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
index 14fccf2..8740a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
@@ -16,7 +16,7 @@
package com.android.systemui.tuner;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import android.annotation.Nullable;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index f2f0382..dea2f50 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -24,7 +24,7 @@
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
new file mode 100644
index 0000000..a068172
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ThemePreference.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.app.AlertDialog;
+import android.app.UiModeManager;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.support.v7.preference.ListPreference;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+
+import libcore.util.Objects;
+
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class ThemePreference extends ListPreference {
+
+ public ThemePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ String def = SystemProperties.get("ro.boot.vendor.overlay.theme");
+ if (TextUtils.isEmpty(def)) {
+ def = getContext().getString(R.string.default_theme);
+ }
+ String[] fileList = new File("/vendor/overlay").list();
+ ArrayList<String> options = fileList != null
+ ? Lists.newArrayList(fileList) : new ArrayList<>();
+ if (!options.contains(def)) {
+ options.add(0, def);
+ }
+ String[] list = options.toArray(new String[options.size()]);
+ setVisible(options.size() > 1);
+ setEntries(list);
+ setEntryValues(list);
+ updateValue();
+ }
+
+ private void updateValue() {
+ setValue(getContext().getSystemService(UiModeManager.class).getTheme());
+ }
+
+ @Override
+ protected void notifyChanged() {
+ super.notifyChanged();
+ if (!Objects.equal(getValue(),
+ getContext().getSystemService(UiModeManager.class).getTheme())) {
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.change_theme_reboot)
+ .setPositiveButton(com.android.internal.R.string.global_action_restart, (d, i)
+ -> getContext().getSystemService(UiModeManager.class)
+ .setTheme(getValue()))
+ .setNegativeButton(android.R.string.cancel, (d, i) -> updateValue())
+ .show();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 7f63418..f835e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -27,7 +27,7 @@
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.plugins.PluginPrefs;
@@ -102,7 +102,9 @@
TunerService.showResetRequest(getContext(), new Runnable() {
@Override
public void run() {
- getActivity().finish();
+ if (getActivity() != null) {
+ getActivity().finish();
+ }
}
});
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 8e0f9b8..ca53bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -23,7 +23,7 @@
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.volume.VolumeDialogController.State;
import java.util.Arrays;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 8ca277e..42b06b2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -797,7 +797,7 @@
// update slider
final boolean enableSlider = !zenMuted;
- final int vlevel = row.ss.muted && (isRingVibrate || !isRingStream && !zenMuted) ? 0
+ final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0
: row.ss.level;
updateVolumeRowSliderH(row, enableSlider, vlevel);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 22d1309..12a00e9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -52,7 +52,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -552,8 +552,9 @@
setToMidnight(nextAlarm);
if (weekRange.compareTo(nextAlarm) >= 0) {
- return ZenModeConfig.toNextAlarmCondition(mContext, now,
- nextAlarmMs, ActivityManager.getCurrentUser());
+ return ZenModeConfig.toTimeCondition(mContext, nextAlarmMs,
+ Math.round((nextAlarmMs - now) / (float) MINUTES_MS),
+ ActivityManager.getCurrentUser(), true);
}
}
return null;
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index b5584f3..6e17cf4 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index fccb2a2..f3be945 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -16,26 +16,24 @@
package com.android.keyguard;
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.mock;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static junit.framework.Assert.*;
-import static org.mockito.Mockito.mock;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KeyguardMessageAreaTest extends SysuiTestCase {
- private Context mContext = InstrumentationRegistry.getTargetContext();
private Handler mHandler = new Handler(Looper.getMainLooper());
private KeyguardMessageArea mMessageArea;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
index 5cb5e68..cb0f7a38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -17,7 +17,7 @@
package com.android.systemui;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.anyString;
@@ -28,27 +28,24 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BatteryMeterDrawableTest {
+public class BatteryMeterDrawableTest extends SysuiTestCase {
- private Context mContext;
private Resources mResources;
private BatteryMeterDrawable mBatteryMeter;
@Before
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
mResources = mContext.getResources();
mBatteryMeter = new BatteryMeterDrawable(mContext, 0);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
new file mode 100644
index 0000000..f87336c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
+import android.app.FragmentManagerNonConfig;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Base class for fragment class tests. Just adding one for any fragment will push it through
+ * general lifecycle events and ensure no basic leaks are happening. This class also implements
+ * the host for subclasses, so they can push it into desired states and do any unit testing
+ * required.
+ */
+public abstract class FragmentTestCase extends LeakCheckedTest {
+
+ private static final int VIEW_ID = 42;
+ private final Class<? extends Fragment> mCls;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private FrameLayout mView;
+ protected FragmentController mFragments;
+ protected Fragment mFragment;
+
+ public FragmentTestCase(Class<? extends Fragment> cls) {
+ mCls = cls;
+ }
+
+ @Before
+ public void setupFragment() throws IllegalAccessException, InstantiationException {
+ mView = new FrameLayout(mContext);
+ mView.setId(VIEW_ID);
+ mHandlerThread = new HandlerThread("FragmentTestThread");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mFragment = mCls.newInstance();
+ postAndWait(() -> {
+ mFragments = FragmentController.createController(new HostCallbacks());
+ mFragments.attachHost(null);
+ mFragments.getFragmentManager().beginTransaction()
+ .replace(VIEW_ID, mFragment)
+ .commit();
+ });
+ }
+
+ @After
+ public void tearDown() {
+ if (mFragments != null) {
+ // Set mFragments to null to let it know not to destroy.
+ postAndWait(() -> mFragments.dispatchDestroy());
+ }
+ mHandlerThread.quit();
+ }
+
+ @Test
+ public void testCreateDestroy() {
+ postAndWait(() -> mFragments.dispatchCreate());
+ destroyFragments();
+ }
+
+ @Test
+ public void testStartStop() {
+ postAndWait(() -> mFragments.dispatchStart());
+ postAndWait(() -> mFragments.dispatchStop());
+ }
+
+ @Test
+ public void testResumePause() {
+ postAndWait(() -> mFragments.dispatchResume());
+ postAndWait(() -> mFragments.dispatchPause());
+ }
+
+ @Test
+ public void testRecreate() {
+ postAndWait(() -> mFragments.dispatchResume());
+ postAndWait(() -> {
+ mFragments.dispatchPause();
+ Parcelable p = mFragments.saveAllState();
+ mFragments.dispatchDestroy();
+
+ mFragments = FragmentController.createController(new HostCallbacks());
+ mFragments.attachHost(null);
+ mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
+ mFragments.dispatchResume();
+ });
+ }
+
+ @Test
+ public void testMultipleResumes() {
+ postAndWait(() -> mFragments.dispatchResume());
+ postAndWait(() -> mFragments.dispatchStop());
+ postAndWait(() -> mFragments.dispatchResume());
+ }
+
+ protected void destroyFragments() {
+ postAndWait(() -> mFragments.dispatchDestroy());
+ mFragments = null;
+ }
+
+ protected void postAndWait(Runnable r) {
+ mHandler.post(r);
+ waitForFragments();
+ }
+
+ protected void waitForFragments() {
+ waitForIdleSync(mHandler);
+ }
+
+ private View findViewById(int id) {
+ return mView.findViewById(id);
+ }
+
+ private class HostCallbacks extends FragmentHostCallback<FragmentTestCase> {
+ public HostCallbacks() {
+ super(getTrackedContext(), FragmentTestCase.this.mHandler, 0);
+ }
+
+ @Override
+ public FragmentTestCase onGetHost() {
+ return FragmentTestCase.this;
+ }
+
+ @Override
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ }
+
+ @Override
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return true; // True for now.
+ }
+
+ @Override
+ public LayoutInflater onGetLayoutInflater() {
+ return LayoutInflater.from(mContext);
+ }
+
+ @Override
+ public boolean onUseFragmentManagerInflaterFactory() {
+ return true;
+ }
+
+ @Override
+ public boolean onHasWindowAnimations() {
+ return false;
+ }
+
+ @Override
+ public int onGetWindowAnimations() {
+ return 0;
+ }
+
+ @Override
+ public void onAttachFragment(Fragment fragment) {
+ }
+
+ @Nullable
+ @Override
+ public View onFindViewById(int id) {
+ return FragmentTestCase.this.findViewById(id);
+ }
+
+ @Override
+ public boolean onHasView() {
+ return true;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
new file mode 100644
index 0000000..d64669d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for tests to check if receivers are left registered, services bound, or other
+ * listeners listening.
+ */
+public class LeakCheckedTest extends SysuiTestCase {
+ private static final String TAG = "LeakCheckedTest";
+
+ private final Map<String, Tracker> mTrackers = new HashMap<>();
+ private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
+ private TrackingContext mTrackedContext;
+
+ @Rule
+ public TestWatcher successWatcher = new TestWatcher() {
+ @Override
+ protected void succeeded(Description description) {
+ verify();
+ }
+ };
+
+ @Before
+ public void setup() {
+ mTrackedContext = new TrackingContext(mContext);
+ addSupportedLeakCheckers();
+ }
+
+ public <T> T getLeakChecker(Class<T> cls) {
+ T obj = (T) mLeakCheckers.get(cls);
+ if (obj == null) {
+ Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
+ }
+ return obj;
+ }
+
+ public Context getTrackedContext() {
+ return mTrackedContext;
+ }
+
+ private Tracker getTracker(String tag) {
+ Tracker t = mTrackers.get(tag);
+ if (t == null) {
+ t = new Tracker();
+ mTrackers.put(tag, t);
+ }
+ return t;
+ }
+
+ public void verify() {
+ mTrackers.values().forEach(Tracker::verify);
+ }
+
+ public static class Tracker {
+ private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
+
+ LeakInfo getLeakInfo(Object object) {
+ LeakInfo leakInfo = mObjects.get(object);
+ if (leakInfo == null) {
+ leakInfo = new LeakInfo();
+ mObjects.put(object, leakInfo);
+ }
+ return leakInfo;
+ }
+
+ private void verify() {
+ mObjects.values().forEach(LeakInfo::verify);
+ }
+ }
+
+ public static class LeakInfo {
+ private List<Throwable> mThrowables = new ArrayList<>();
+
+ private LeakInfo() {
+ }
+
+ private void addAllocation(Throwable t) {
+ // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
+ mThrowables.add(t);
+ }
+
+ private void clearAllocations() {
+ mThrowables.clear();
+ }
+
+ public void verify() {
+ if (mThrowables.size() == 0) return;
+ Log.e(TAG, "Listener or binding not properly released");
+ for (Throwable t : mThrowables) {
+ Log.e(TAG, "Allocation found", t);
+ }
+ StringWriter writer = new StringWriter();
+ mThrowables.get(0).printStackTrace(new PrintWriter(writer));
+ Assert.fail("Listener or binding not properly released\n"
+ + writer.toString());
+ }
+ }
+
+ private void addSupportedLeakCheckers() {
+ addListening("bluetooth", BluetoothController.class);
+ addListening("location", LocationController.class);
+ addListening("rotation", RotationLockController.class);
+ addListening("zen", ZenModeController.class);
+ addListening("cast", CastController.class);
+ addListening("hotspot", HotspotController.class);
+ addListening("flashlight", FlashlightController.class);
+ addListening("user", UserInfoController.class);
+ addListening("keyguard", KeyguardMonitor.class);
+ addListening("battery", BatteryController.class);
+ addListening("security", SecurityController.class);
+ addListening("profile", ManagedProfileController.class);
+ addListening("alarm", NextAlarmController.class);
+ NetworkController network = addListening("network", NetworkController.class);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker("emergency").getLeakInfo(invocation.getArguments()[0])
+ .addAllocation(new Throwable());
+ return null;
+ }
+ }).when(network).addEmergencyListener(any());
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker("emergency").getLeakInfo(invocation.getArguments()[0]).clearAllocations();
+ return null;
+ }
+ }).when(network).removeEmergencyListener(any());
+ DataSaverController datasaver = addListening("datasaver", DataSaverController.class);
+ when(network.getDataSaverController()).thenReturn(datasaver);
+ }
+
+ private <T extends CallbackController> T addListening(final String tag, Class<T> cls) {
+ T mock = mock(cls);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker(tag).getLeakInfo(invocation.getArguments()[0])
+ .addAllocation(new Throwable());
+ return null;
+ }
+ }).when(mock).addCallback(any());
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
+ return null;
+ }
+ }).when(mock).removeCallback(any());
+ mLeakCheckers.put(cls, mock);
+ return mock;
+ }
+
+ class TrackingContext extends ContextWrapper {
+ public TrackingContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiver(receiver, filter);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
+ }
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler) {
+ getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+ scheduler);
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ getTracker("receiver").getLeakInfo(receiver).clearAllocations();
+ super.unregisterReceiver(receiver);
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+ getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindService(service, conn, flags);
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindServiceAsUser(service, conn, flags, handler, user);
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ UserHandle user) {
+ getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindServiceAsUser(service, conn, flags, user);
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ getTracker("service").getLeakInfo(conn).clearAllocations();
+ super.unbindService(conn);
+ }
+
+ @Override
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ getTracker("component").getLeakInfo(callback).addAllocation(new Throwable());
+ super.registerComponentCallbacks(callback);
+ }
+
+ @Override
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ getTracker("component").getLeakInfo(callback).clearAllocations();
+ super.unregisterComponentCallbacks(callback);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index d943eb6..5dac8e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -20,6 +20,10 @@
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
+
+import com.android.systemui.utils.TestableContext;
+
+import org.junit.After;
import org.junit.Before;
/**
@@ -28,11 +32,16 @@
public class SysuiTestCase {
private Handler mHandler;
- protected Context mContext;
+ protected TestableContext mContext;
@Before
public void SysuiSetup() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
+ mContext = new TestableContext(InstrumentationRegistry.getTargetContext());
+ }
+
+ @After
+ public void cleanup() throws Exception {
+ mContext.getSettingsProvider().clearOverrides(this);
}
protected Context getContext() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 39b6412..5c87fb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -17,9 +17,11 @@
package com.android.systemui.power;
import static android.test.MoreAsserts.assertNotEqual;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
@@ -29,9 +31,11 @@
import android.app.Notification;
import android.app.NotificationManager;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,7 +43,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class PowerNotificationWarningsTest {
+public class PowerNotificationWarningsTest extends SysuiTestCase {
private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
private PowerNotificationWarnings mPowerNotificationWarnings;
@@ -47,7 +51,7 @@
public void setUp() throws Exception {
// Test Instance.
mPowerNotificationWarnings = new PowerNotificationWarnings(
- InstrumentationRegistry.getTargetContext(), mMockNotificationManager, null);
+ mContext, mMockNotificationManager, null);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
new file mode 100644
index 0000000..6ceaead
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.FragmentTestCase;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class QSFragmentTest extends FragmentTestCase {
+
+ public QSFragmentTest() {
+ super(QSFragment.class);
+ }
+
+ @Test
+ public void testListening() {
+ QSFragment qs = (QSFragment) mFragment;
+ postAndWait(() -> mFragments.dispatchResume());
+ UserSwitcherController userSwitcher = mock(UserSwitcherController.class);
+ KeyguardMonitor keyguardMonitor = getLeakChecker(KeyguardMonitor.class);
+ when(userSwitcher.getKeyguardMonitor()).thenReturn(keyguardMonitor);
+ when(userSwitcher.getUsers()).thenReturn(new ArrayList<>());
+ QSTileHost host = new QSTileHost(getTrackedContext(),
+ mock(PhoneStatusBar.class),
+ getLeakChecker(BluetoothController.class),
+ getLeakChecker(LocationController.class),
+ getLeakChecker(RotationLockController.class),
+ getLeakChecker(NetworkController.class),
+ getLeakChecker(ZenModeController.class),
+ getLeakChecker(HotspotController.class),
+ getLeakChecker(CastController.class),
+ getLeakChecker(FlashlightController.class),
+ userSwitcher,
+ getLeakChecker(UserInfoController.class),
+ keyguardMonitor,
+ getLeakChecker(SecurityController.class),
+ getLeakChecker(BatteryController.class),
+ mock(StatusBarIconController.class),
+ getLeakChecker(NextAlarmController.class));
+ qs.setHost(host);
+ Handler h = new Handler(host.getLooper());
+
+ qs.setListening(true);
+ waitForIdleSync(h);
+
+ qs.setListening(false);
+ waitForIdleSync(h);
+
+ host.destroy();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 8eecfcf..5401c30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -18,6 +18,7 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -26,11 +27,12 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,13 +40,13 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class TileLayoutTest {
- private Context mContext = InstrumentationRegistry.getTargetContext();
- private final TileLayout mTileLayout = new TileLayout(mContext);
+public class TileLayoutTest extends SysuiTestCase {
+ private TileLayout mTileLayout;
private int mLayoutSizeForOneTile;
@Before
public void setUp() throws Exception {
+ mTileLayout = new TileLayout(mContext);
// Layout needs to leave space for the tile margins. Three times the margin size is
// sufficient for any number of columns.
mLayoutSizeForOneTile =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index d7ff04f..782a489 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -16,7 +16,7 @@
package com.android.systemui.qs.external;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
@@ -25,12 +25,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.Service;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.ServiceInfo;
@@ -38,19 +35,16 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quicksettings.IQSService;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
-import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -61,7 +55,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class TileLifecycleManagerTest {
+public class TileLifecycleManagerTest extends SysuiTestCase {
private static final int TEST_FAIL_TIMEOUT = 5000;
private final Context mMockContext = Mockito.mock(Context.class);
@@ -78,8 +72,7 @@
@Before
public void setUp() throws Exception {
setPackageEnabled(true);
- mTileServiceComponentName = new ComponentName(
- InstrumentationRegistry.getTargetContext(), "FakeTileService.class");
+ mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class");
// Stub.asInterface will just return itself.
when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 6c9cfe0..136e7c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -35,7 +35,7 @@
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
import com.android.systemui.SysuiTestCase;
-import org.junit.After;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestWatcher;
@@ -118,7 +118,7 @@
// Trigger blank callbacks to always get the current state (some tests don't trigger
// changes from default state).
- mNetworkController.addSignalCallback(mock(SignalCallback.class));
+ mNetworkController.addCallback(mock(SignalCallback.class));
mNetworkController.addEmergencyListener(null);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java
new file mode 100644
index 0000000..34f2e01
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeContentResolver.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.util.ArraySet;
+
+import com.google.android.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Alternative to a MockContentResolver that falls back to real providers.
+ */
+public class FakeContentResolver extends ContentResolver {
+
+ private final Map<String, ContentProvider> mProviders = Maps.newHashMap();
+ private final ContentResolver mParent;
+ private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
+ private boolean mFallbackToExisting;
+
+ public FakeContentResolver(Context context) {
+ super(context);
+ mParent = context.getContentResolver();
+ mFallbackToExisting = true;
+ }
+
+ /**
+ * Sets whether existing providers should be returned when a mock does not exist.
+ * The default is true.
+ */
+ public void setFallbackToExisting(boolean fallbackToExisting) {
+ mFallbackToExisting = fallbackToExisting;
+ }
+
+ /**
+ * Adds access to a provider based on its authority
+ *
+ * @param name The authority name associated with the provider.
+ * @param provider An instance of {@link android.content.ContentProvider} or one of its
+ * subclasses, or null.
+ */
+ public void addProvider(String name, ContentProvider provider) {
+ mProviders.put(name, provider);
+ }
+
+ @Override
+ protected IContentProvider acquireProvider(Context context, String name) {
+ final ContentProvider provider = mProviders.get(name);
+ if (provider != null) {
+ return provider.getIContentProvider();
+ } else {
+ return mFallbackToExisting ? mParent.acquireProvider(name) : null;
+ }
+ }
+
+ @Override
+ protected IContentProvider acquireExistingProvider(Context context, String name) {
+ final ContentProvider provider = mProviders.get(name);
+ if (provider != null) {
+ return provider.getIContentProvider();
+ } else {
+ return mFallbackToExisting ? mParent.acquireExistingProvider(
+ new Uri.Builder().authority(name).build()) : null;
+ }
+ }
+
+ @Override
+ public boolean releaseProvider(IContentProvider provider) {
+ if (!mFallbackToExisting) return true;
+ if (mInUse.contains(provider)) {
+ mInUse.remove(provider);
+ return true;
+ }
+ return mParent.releaseProvider(provider);
+ }
+
+ @Override
+ protected IContentProvider acquireUnstableProvider(Context c, String name) {
+ final ContentProvider provider = mProviders.get(name);
+ if (provider != null) {
+ return provider.getIContentProvider();
+ } else {
+ return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null;
+ }
+ }
+
+ @Override
+ public boolean releaseUnstableProvider(IContentProvider icp) {
+ if (!mFallbackToExisting) return true;
+ if (mInUse.contains(icp)) {
+ mInUse.remove(icp);
+ return true;
+ }
+ return mParent.releaseUnstableProvider(icp);
+ }
+
+ @Override
+ public void unstableProviderDied(IContentProvider icp) {
+ if (!mFallbackToExisting) return;
+ if (mInUse.contains(icp)) {
+ return;
+ }
+ mParent.unstableProviderDied(icp);
+ }
+
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ if (!mFallbackToExisting) return;
+ if (!mProviders.containsKey(uri.getAuthority())) {
+ super.notifyChange(uri, observer, syncToNetwork);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java
new file mode 100644
index 0000000..f40fe4c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProvider.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.test.mock.MockContentProvider;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider.Builder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Allows calls to android.provider.Settings to be tested easier. A SettingOverride
+ * can be acquired and a set of specific settings can be set to a value (and not changed
+ * in the system when set), so that they can be tested without breaking the test device.
+ * <p>
+ * To use, in the before method acquire the override add all settings that will affect if
+ * your test passes or not.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * mSettingOverride = mTestableContext.getSettingsProvider().acquireOverridesBuilder()
+ * .addSetting("secure", Secure.USER_SETUP_COMPLETE, "0")
+ * .build();
+ * }
+ * </pre>
+ *
+ * Then in the after free up the settings.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * mSettingOverride.release();
+ * }
+ * </pre>
+ */
+public class FakeSettingsProvider extends MockContentProvider {
+
+ private static final String TAG = "FakeSettingsProvider";
+ private static final boolean DEBUG = false;
+
+ // Number of times to try to acquire a setting if in use.
+ private static final int MAX_TRIES = 10;
+ // Time to wait for each setting. WAIT_TIMEOUT * MAX_TRIES will be the maximum wait time
+ // for a setting.
+ private static final long WAIT_TIMEOUT = 1000;
+
+ private final Map<String, SettingOverrider> mOverrideMap = new ArrayMap<>();
+ private final Map<SysuiTestCase, List<SettingOverrider>> mOwners = new ArrayMap<>();
+
+ private static FakeSettingsProvider sInstance;
+ private final ContentProviderClient mSettings;
+ private final ContentResolver mResolver;
+
+ private FakeSettingsProvider(ContentProviderClient settings, ContentResolver resolver) {
+ mSettings = settings;
+ mResolver = resolver;
+ }
+
+ public Builder acquireOverridesBuilder(SysuiTestCase test) {
+ return new Builder(this, test);
+ }
+
+ public void clearOverrides(SysuiTestCase test) {
+ List<SettingOverrider> overrides = mOwners.remove(test);
+ if (overrides != null) {
+ overrides.forEach(override -> override.ensureReleased());
+ }
+ }
+
+ public Bundle call(String method, String arg, Bundle extras) {
+ // Methods are "GET_system", "GET_global", "PUT_secure", etc.
+ final String[] commands = method.split("_", 2);
+ final String op = commands[0];
+ final String table = commands[1];
+
+ synchronized (mOverrideMap) {
+ SettingOverrider overrider = mOverrideMap.get(key(table, arg));
+ if (overrider == null) {
+ // Fall through to real settings.
+ try {
+ if (DEBUG) Log.d(TAG, "Falling through to real settings " + method);
+ // TODO: Add our own version of caching to handle this.
+ Bundle call = mSettings.call(method, arg, extras);
+ call.remove(Settings.CALL_METHOD_TRACK_GENERATION_KEY);
+ return call;
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ String value;
+ Bundle out = new Bundle();
+ switch (op) {
+ case "GET":
+ value = overrider.get(table, arg);
+ if (value != null) {
+ out.putString(Settings.NameValueTable.VALUE, value);
+ }
+ break;
+ case "PUT":
+ value = extras.getString(Settings.NameValueTable.VALUE, null);
+ if (value != null) {
+ overrider.put(table, arg, value);
+ } else {
+ overrider.remove(table, arg);
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown command " + method);
+ }
+ return out;
+ }
+ }
+
+ private void acquireSettings(SettingOverrider overridder, Set<String> keys,
+ SysuiTestCase owner) throws AcquireTimeoutException {
+ synchronized (mOwners) {
+ List<SettingOverrider> list = mOwners.get(owner);
+ if (list == null) {
+ list = new ArrayList<>();
+ mOwners.put(owner, list);
+ }
+ list.add(overridder);
+ }
+ synchronized (mOverrideMap) {
+ for (int i = 0; i < MAX_TRIES; i++) {
+ if (checkKeys(keys, false)) break;
+ try {
+ if (DEBUG) Log.d(TAG, "Waiting for contention to finish");
+ mOverrideMap.wait(WAIT_TIMEOUT);
+ } catch (InterruptedException e) {
+ }
+ }
+ checkKeys(keys, true);
+ for (String key : keys) {
+ if (DEBUG) Log.d(TAG, "Acquiring " + key);
+ mOverrideMap.put(key, overridder);
+ }
+ }
+ }
+
+ private void releaseSettings(Set<String> keys) {
+ synchronized (mOverrideMap) {
+ for (String key : keys) {
+ if (DEBUG) Log.d(TAG, "Releasing " + key);
+ mOverrideMap.remove(key);
+ }
+ if (DEBUG) Log.d(TAG, "Notifying");
+ mOverrideMap.notify();
+ }
+ }
+
+ @VisibleForTesting
+ public Object getLock() {
+ return mOverrideMap;
+ }
+
+ private boolean checkKeys(Set<String> keys, boolean shouldThrow)
+ throws AcquireTimeoutException {
+ for (String key : keys) {
+ if (mOverrideMap.containsKey(key)) {
+ if (shouldThrow) {
+ throw new AcquireTimeoutException("Could not acquire " + key);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static class SettingOverrider {
+ private final Set<String> mValidKeys;
+ private final Map<String, String> mValueMap = new ArrayMap<>();
+ private final FakeSettingsProvider mProvider;
+ private boolean mReleased;
+
+ private SettingOverrider(Set<String> keys, FakeSettingsProvider provider) {
+ mValidKeys = new ArraySet<>(keys);
+ mProvider = provider;
+ }
+
+ private void ensureReleased() {
+ if (!mReleased) {
+ release();
+ }
+ }
+
+ public void release() {
+ mProvider.releaseSettings(mValidKeys);
+ mReleased = true;
+ }
+
+ private void putDirect(String key, String value) {
+ mValueMap.put(key, value);
+ }
+
+ public void put(String table, String key, String value) {
+ if (!mValidKeys.contains(key(table, key))) {
+ throw new IllegalArgumentException("Key " + table + " " + key
+ + " not acquired for this overrider");
+ }
+ mValueMap.put(key(table, key), value);
+ }
+
+ public void remove(String table, String key) {
+ if (!mValidKeys.contains(key(table, key))) {
+ throw new IllegalArgumentException("Key " + table + " " + key
+ + " not acquired for this overrider");
+ }
+ mValueMap.remove(key(table, key));
+ }
+
+ public String get(String table, String key) {
+ if (!mValidKeys.contains(key(table, key))) {
+ throw new IllegalArgumentException("Key " + table + " " + key
+ + " not acquired for this overrider");
+ }
+ Log.d(TAG, "Get " + table + " " + key + " " + mValueMap.get(key(table, key)));
+ return mValueMap.get(key(table, key));
+ }
+
+ public static class Builder {
+ private final FakeSettingsProvider mProvider;
+ private final SysuiTestCase mOwner;
+ private Set<String> mKeys = new ArraySet<>();
+ private Map<String, String> mValues = new ArrayMap<>();
+
+ private Builder(FakeSettingsProvider provider, SysuiTestCase test) {
+ mProvider = provider;
+ mOwner = test;
+ }
+
+ public Builder addSetting(String table, String key) {
+ mKeys.add(key(table, key));
+ return this;
+ }
+
+ public Builder addSetting(String table, String key, String value) {
+ addSetting(table, key);
+ mValues.put(key(table, key), value);
+ return this;
+ }
+
+ public SettingOverrider build() throws AcquireTimeoutException {
+ SettingOverrider overrider = new SettingOverrider(mKeys, mProvider);
+ mProvider.acquireSettings(overrider, mKeys, mOwner);
+ mValues.forEach((key, value) -> overrider.putDirect(key, value));
+ return overrider;
+ }
+ }
+ }
+
+ public static class AcquireTimeoutException extends Exception {
+ public AcquireTimeoutException(String str) {
+ super(str);
+ }
+ }
+
+ private static String key(String table, String key) {
+ return table + "_" + key;
+ }
+
+ /**
+ * Since the settings provider is cached inside android.provider.Settings, this must
+ * be gotten statically to ensure there is only one instance referenced.
+ * @param settings
+ */
+ public static FakeSettingsProvider getFakeSettingsProvider(ContentProviderClient settings,
+ ContentResolver resolver) {
+ if (sInstance == null) {
+ sInstance = new FakeSettingsProvider(settings, resolver);
+ }
+ return sInstance;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java
new file mode 100644
index 0000000..63bb5e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/FakeSettingsProviderTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ContentResolver;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.FakeSettingsProvider.AcquireTimeoutException;
+import com.android.systemui.utils.FakeSettingsProvider.SettingOverrider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class FakeSettingsProviderTest extends SysuiTestCase {
+
+ public static final String NONEXISTENT_SETTING = "nonexistent_setting";
+ private static final String TAG = "FakeSettingsProviderTest";
+ private SettingOverrider mOverrider;
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setup() throws AcquireTimeoutException {
+ mOverrider = mContext.getSettingsProvider().acquireOverridesBuilder(this)
+ .addSetting("secure", NONEXISTENT_SETTING)
+ .addSetting("global", NONEXISTENT_SETTING, "initial value")
+ .addSetting("global", Global.DEVICE_PROVISIONED)
+ .build();
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ @After
+ public void teardown() {
+ if (mOverrider != null) {
+ mOverrider.release();
+ }
+ }
+
+ @Test
+ public void testInitialValueSecure() {
+ String value = Secure.getString(mContentResolver, NONEXISTENT_SETTING);
+ assertNull(value);
+ }
+
+ @Test
+ public void testInitialValueGlobal() {
+ String value = Global.getString(mContentResolver, NONEXISTENT_SETTING);
+ assertEquals("initial value", value);
+ }
+
+ @Test
+ public void testSeparateTables() {
+ Secure.putString(mContentResolver, NONEXISTENT_SETTING, "something");
+ Global.putString(mContentResolver, NONEXISTENT_SETTING, "else");
+ assertEquals("something", Secure.getString(mContentResolver, NONEXISTENT_SETTING));
+ assertEquals("something", mOverrider.get("secure", NONEXISTENT_SETTING));
+ assertEquals("else", Global.getString(mContentResolver, NONEXISTENT_SETTING));
+ assertEquals("else", mOverrider.get("global", NONEXISTENT_SETTING));
+ }
+
+ @Test
+ public void testPassThrough() {
+ // Grab the value of a setting that is not overridden.
+ assertTrue(Secure.getInt(mContentResolver, Secure.USER_SETUP_COMPLETE, 0) != 0);
+ }
+
+ @Test
+ public void testOverrideExisting() {
+ // Grab the value of a setting that is overridden and will be different than the actual
+ // value.
+ assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+ }
+
+ @Test
+ public void testRelease() {
+ // Verify different value.
+ assertNull(Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+ mOverrider.release();
+ mOverrider = null;
+ // Verify actual value after release.
+ assertEquals("1", Global.getString(mContentResolver, Global.DEVICE_PROVISIONED));
+ }
+
+ @Test
+ public void testAutoRelease() throws Exception {
+ super.cleanup();
+ mContext.getSettingsProvider().acquireOverridesBuilder(this)
+ .addSetting("global", Global.DEVICE_PROVISIONED)
+ .build();
+ }
+
+ @Test
+ public void testContention() throws AcquireTimeoutException, InterruptedException {
+ SettingOverrider[] overriders = new SettingOverrider[2];
+ Object lock = new Object();
+ String secure = "secure";
+ String key = "something shared";
+ String[] result = new String[1];
+ overriders[0] = mContext.getSettingsProvider().acquireOverridesBuilder(this)
+ .addSetting(secure, key, "Some craziness")
+ .build();
+ synchronized (lock) {
+ HandlerThread t = runOnHandler(() -> {
+ try {
+ // Grab the lock that will be used for the settings ownership to ensure
+ // we have some contention going on.
+ synchronized (mContext.getSettingsProvider().getLock()) {
+ synchronized (lock) {
+ // Let the other thread know to release the settings, but it won't
+ // be able to until this thread waits in the build() method.
+ lock.notify();
+ }
+ overriders[1] = mContext.getSettingsProvider()
+ .acquireOverridesBuilder(FakeSettingsProviderTest.this)
+ .addSetting(secure, key, "default value")
+ .build();
+ // Ensure that the default is the one we set, and not left over from
+ // the other setting override.
+ result[0] = Settings.Secure.getString(mContentResolver, key);
+ synchronized (lock) {
+ // Let the main thread know we are done.
+ lock.notify();
+ }
+ }
+ } catch (AcquireTimeoutException e) {
+ Log.e(TAG, "Couldn't acquire setting", e);
+ }
+ });
+ // Wait for the thread to hold the acquire lock, then release the settings.
+ lock.wait();
+ overriders[0].release();
+ // Wait for the thread to be done getting the value.
+ lock.wait();
+ // Quit and cleanup.
+ t.quitSafely();
+ assertNotNull(overriders[1]);
+ overriders[1].release();
+ }
+ // Verify the value was the expected one from the thread's SettingOverride.
+ assertEquals("default value", result[0]);
+ }
+
+ private HandlerThread runOnHandler(Runnable r) {
+ HandlerThread t = new HandlerThread("Test Thread");
+ t.start();
+ new Handler(t.getLooper()).post(r);
+ return t;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
new file mode 100644
index 0000000..5179823
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.provider.Settings;
+
+public class TestableContext extends ContextWrapper {
+
+ private final FakeContentResolver mFakeContentResolver;
+ private final FakeSettingsProvider mSettingsProvider;
+
+ public TestableContext(Context base) {
+ super(base);
+ mFakeContentResolver = new FakeContentResolver(base);
+ ContentProviderClient settings = base.getContentResolver()
+ .acquireContentProviderClient(Settings.AUTHORITY);
+ mSettingsProvider = FakeSettingsProvider.getFakeSettingsProvider(settings,
+ mFakeContentResolver);
+ mFakeContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider);
+ }
+
+ public FakeSettingsProvider getSettingsProvider() {
+ return mSettingsProvider;
+ }
+
+ @Override
+ public FakeContentResolver getContentResolver() {
+ return mFakeContentResolver;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ // Return this so its always a TestableContext.
+ return this;
+ }
+}
diff --git a/preloaded-classes b/preloaded-classes
index 45734b6..a79ae50 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -327,9 +327,6 @@
android.app.ActivityManager$StackId
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
-android.app.ActivityManagerNative
-android.app.ActivityManagerNative$1
-android.app.ActivityManagerProxy
android.app.ActivityOptions
android.app.ActivityThread
android.app.ActivityThread$1
@@ -1729,9 +1726,9 @@
android.os.Vibrator
android.os.ZygoteStartFailedEx
android.os.health.SystemHealthManager
-android.os.storage.IMountService
-android.os.storage.IMountService$Stub
-android.os.storage.IMountService$Stub$Proxy
+android.os.storage.IStorageManager
+android.os.storage.IStorageManager$Stub
+android.os.storage.IStorageManager$Stub$Proxy
android.os.storage.StorageManager
android.os.storage.StorageVolume
android.os.storage.StorageVolume$1
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 48bc27e..9b4b186 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -22,6 +22,27 @@
// Wrapper for System UI log events
message MetricsEvent {
+ // Types of events
+ enum Type {
+ // Unknown
+ TYPE_UNKNOWN = 0;
+
+ // The view became visible to the user.
+ TYPE_OPEN = 1;
+
+ // The view became hidden.
+ TYPE_CLOSE = 2;
+
+ // The view switched to detail mode (most relevant for quick settings tiles)
+ TYPE_DETAIL = 3;
+
+ // The view or control was activated.
+ TYPE_ACTION = 4;
+
+ // The view or control was dismissed.
+ TYPE_DISMISS = 5;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -2627,6 +2648,11 @@
// ACTION: Logs the end to end time taken by all provisioning tasks.
PROVISIONING_TOTAL_TASK_TIME_MS = 627;
+ // OPEN: Settings > Privacy
+ // CATEGORY: SETTINGS
+ // OS: O
+ ENTERPRISE_PRIVACY_SETTINGS = 628;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/Android.mk b/services/Android.mk
index 3385bed..2911983 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -22,6 +22,7 @@
core \
accessibility \
appwidget \
+ autofill \
backup \
devicepolicy \
midi \
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index bf60e47..6404604 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1593,14 +1593,6 @@
// Make sure the package runs under the caller uid.
mSecurityPolicy.enforceCallFromPackage(callingPackage);
-
- final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0;
- if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
- throw new IllegalArgumentException("RemoteViews for widget update exceeds"
- + " maximum bitmap memory usage (used: " + bitmapMemoryUsage
- + ", max: " + mMaxWidgetBitmapMemory + ")");
- }
-
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -1812,6 +1804,15 @@
// For a full update we replace the RemoteViews completely.
widget.views = views;
}
+ int memoryUsage;
+ if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
+ (widget.views != null) &&
+ ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) {
+ widget.views = null;
+ throw new IllegalArgumentException("RemoteViews for widget update exceeds"
+ + " maximum bitmap memory usage (used: " + memoryUsage
+ + ", max: " + mMaxWidgetBitmapMemory + ")");
+ }
scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
diff --git a/services/autofill/Android.mk b/services/autofill/Android.mk
new file mode 100644
index 0000000..a1f19fd
--- /dev/null
+++ b/services/autofill/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.autofill
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
new file mode 100644
index 0000000..d70c439
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static android.Manifest.permission.MANAGE_AUTO_FILL;
+import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.service.autofill.IAutoFillManagerService;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Entry point service for auto-fill management.
+ *
+ * <p>This service provides the {@link IAutoFillManagerService} implementation and keeps a list of
+ * {@link AutoFillManagerServiceImpl} per user; the real work is done by
+ * {@link AutoFillManagerServiceImpl} itself.
+ */
+public final class AutoFillManagerService extends SystemService {
+
+ private static final String TAG = "AutoFillManagerService";
+ static final boolean DEBUG = true; // TODO: change to false once stable
+
+ private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS;
+
+ private static final int ARG_NOT_USED = 0;
+
+ protected static final int MSG_UNBIND = 1;
+
+ private final AutoFillManagerServiceStub mServiceStub;
+ private final Context mContext;
+ private final ContentResolver mResolver;
+
+ private final Object mLock = new Object();
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UNBIND:
+ removeStaleServiceForUser(msg.arg1);
+ return;
+ case MSG_SHOW_ALL_NOTIFICATIONS:
+ showAllNotifications();
+ return;
+ default:
+ Slog.w(TAG, "Invalid message: " + msg);
+ }
+ }
+
+ };
+
+ /**
+ * Cache of {@link AutoFillManagerServiceImpl} per user id.
+ * <p>
+ * It has to be mapped by user id because the same current user could have simultaneous sessions
+ * associated to different user profiles (for example, in a multi-window environment or when
+ * device has work profiles).
+ * <p>
+ * Entries on this cache are added on demand and removed when:
+ * <ol>
+ * <li>An auto-fill service app is removed.
+ * <li>The {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} for an user change.
+ * <li>It has not been interacted with for {@link #SERVICE_BINDING_LIFETIME_MS} ms.
+ * </ol>
+ */
+ @GuardedBy("mLock")
+ private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>();
+
+ public AutoFillManagerService(Context context) {
+ super(context);
+
+ mContext = context;
+ mResolver = context.getContentResolver();
+ mServiceStub = new AutoFillManagerServiceStub();
+ }
+
+ @Override
+ public void onStart() {
+ if (DEBUG) Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE);
+ publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ new SettingsObserver(BackgroundThread.getHandler());
+ }
+ if (phase == PHASE_BOOT_COMPLETED) {
+ // TODO: if sent right away, the notification is not displayed. Since the notification
+ // mechanism is a temporary approach anyways, just delay it..
+ if (DEBUG)
+ Slog.d(TAG, "Showing notifications in " + SHOW_ALL_NOTIFICATIONS_DELAY_MS + "ms");
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ALL_NOTIFICATIONS),
+ SHOW_ALL_NOTIFICATIONS_DELAY_MS);
+ }
+ }
+
+ private AutoFillManagerServiceImpl newServiceForUser(int userId) {
+ ComponentName serviceComponent = null;
+ ServiceInfo serviceInfo = null;
+ final String componentName = Settings.Secure.getStringForUser(
+ mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+ if (!TextUtils.isEmpty(componentName)) {
+ try {
+ serviceComponent = ComponentName.unflattenFromString(componentName);
+ serviceInfo =
+ AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
+ } catch (RuntimeException | RemoteException e) {
+ Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+ return null;
+ }
+ }
+
+ if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
+ + serviceComponent + ", info: " + serviceInfo);
+ if (serviceInfo == null) {
+ Slog.w(TAG, "no service info for " + serviceComponent);
+ return null;
+ }
+ return new AutoFillManagerServiceImpl(this, mContext, mLock, FgThread.getHandler(), userId,
+ serviceInfo.applicationInfo.uid, serviceComponent, SERVICE_BINDING_LIFETIME_MS);
+ }
+
+ /**
+ * Gets the service instance for an user.
+ *
+ * <p>First it tries to return the existing instance from the cache; if it's not cached, it
+ * creates a new instance and caches it.
+ */
+ private AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
+ AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service != null) {
+ if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId);
+ service.setLifeExpectancy(SERVICE_BINDING_LIFETIME_MS);
+ } else {
+ service = newServiceForUser(userId);
+ if (service == null) {
+ // Already logged
+ return null;
+ }
+ if (DEBUG) Log.d(TAG, "creating new cached service for userId " + userId);
+ service.startLocked();
+ mServicesCache.put(userId, service);
+ }
+ // Keep service connection alive for a while, in case user needs to interact with it
+ // (for example, to save the data that was inputted in)
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UNBIND, userId, ARG_NOT_USED),
+ SERVICE_BINDING_LIFETIME_MS);
+ return service;
+ }
+
+ /**
+ * Removes a cached service, but respecting its TTL.
+ */
+ private void removeStaleServiceForUser(int userId) {
+ synchronized (mLock) {
+ removeCachedService(userId, false);
+ }
+ }
+
+ /**
+ * Removes a cached service, even if it has TTL.
+ */
+ void removeCachedServiceForUserLocked(int userId) {
+ removeCachedService(userId, true);
+ }
+
+ private void removeCachedService(int userId, boolean force) {
+ if (DEBUG) Log.d(TAG, "removing cached service for userId " + userId);
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service == null) {
+ Log.w(TAG, "removeCachedServiceForUser(): no cached service for userId " + userId);
+ return;
+ }
+ if (!force) {
+ // Check TTL first.
+ final long now = SystemClock.uptimeMillis();
+ if (service.mEstimateTimeOfDeath > now) {
+ if (DEBUG) {
+ final StringBuilder msg = new StringBuilder("service has some TTL left: ");
+ TimeUtils.formatDuration(service.mEstimateTimeOfDeath - now, msg);
+ Log.d(TAG, msg.toString());
+ }
+ return;
+ }
+ }
+ mServicesCache.delete(userId);
+ service.stopLocked();
+
+ }
+
+ final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
+
+ @Override
+ public void requestAutoFill(int userId, IBinder activityToken) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.requestAutoFill(activityToken);
+ }
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingPermission(
+ Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump autofill from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ synchronized (mLock) {
+ final int size = mServicesCache.size();
+ pw.print("Cached services: ");
+ if (size == 0) {
+ pw.println("none");
+ } else {
+ pw.println(size);
+ for (int i = 0; i < size; i++) {
+ pw.print("\nService at index "); pw.println(i);
+ final AutoFillManagerServiceImpl impl = mServicesCache.valueAt(i);
+ impl.dumpLocked(" ", pw);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ (new AutoFillManagerServiceShellCommand(this)).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.AUTO_FILL_SERVICE), false, this, UserHandle.USER_ALL);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
+ synchronized (mLock) {
+ removeCachedServiceForUserLocked(userId);
+ final ComponentName serviceComponent = getProviderForUser(userId);
+ if (serviceComponent== null) {
+ cancelNotificationLocked(userId);
+ } else {
+ showNotification(serviceComponent, userId);
+ }
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // TODO: temporary code using a notification to request auto-fill. //
+ // Will be removed once UX decide the right way to present it to the user //
+ ////////////////////////////////////////////////////////////////////////////
+
+ // TODO: remove from frameworks/base/core/res/AndroidManifest.xml once it's not used anymore
+ private static final String NOTIFICATION_INTENT =
+ "com.android.internal.autofill.action.REQUEST_AUTOFILL";
+ private static final String EXTRA_USER_ID = "user_id";
+
+ private static final int MSG_SHOW_ALL_NOTIFICATIONS = 42;
+ private static final int SHOW_ALL_NOTIFICATIONS_DELAY_MS = 5000;
+
+ private BroadcastReceiver mNotificationReceiver;
+
+ final class NotificationReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int userId = intent.getIntExtra(EXTRA_USER_ID, -1);
+ if (DEBUG) Slog.d(TAG, "Requesting autofill by notification for user " + userId);
+ synchronized (mLock) {
+ final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service == null) {
+ Slog.w(TAG, "no auto-fill service for user " + userId);
+ } else {
+ service.requestAutoFill(null);
+ }
+ }
+ }
+ }
+
+ private ComponentName getProviderForUser(int userId) {
+ ComponentName serviceComponent = null;
+ ServiceInfo serviceInfo = null;
+ final String componentName = Settings.Secure.getStringForUser(
+ mResolver, Settings.Secure.AUTO_FILL_SERVICE, userId);
+ if (!TextUtils.isEmpty(componentName)) {
+ try {
+ serviceComponent = ComponentName.unflattenFromString(componentName);
+ serviceInfo =
+ AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, userId);
+ } catch (RuntimeException | RemoteException e) {
+ Slog.wtf(TAG, "Bad auto-fill service name " + componentName, e);
+ return null;
+ }
+ }
+
+ if (DEBUG) Slog.d(TAG, "getServiceComponentForUser(" + userId + "): component="
+ + serviceComponent + ", info: " + serviceInfo);
+ if (serviceInfo == null) {
+ Slog.w(TAG, "no service info for " + serviceComponent);
+ return null;
+ }
+ return serviceComponent;
+ }
+
+ private void showAllNotifications() {
+ final UserManager userManager =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+ final List<UserInfo> allUsers = userManager.getUsers(true);
+
+ for (UserInfo user : allUsers) {
+ final ComponentName serviceComponent = getProviderForUser(user.id);
+ if (serviceComponent != null) {
+ showNotification(serviceComponent, user.id);
+ }
+ }
+ }
+
+ private void showNotification(ComponentName serviceComponent, int userId) {
+ if (DEBUG) Log.d(TAG, "showNotification() for " + userId + ": " + serviceComponent);
+
+ synchronized (mLock) {
+ if (mNotificationReceiver == null) {
+ mNotificationReceiver = new NotificationReceiver();
+ mContext.registerReceiver(mNotificationReceiver,
+ new IntentFilter(NOTIFICATION_INTENT));
+ }
+ }
+
+ final Intent intent = new Intent(NOTIFICATION_INTENT);
+ intent.putExtra(EXTRA_USER_ID, userId);
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ final String packageName = serviceComponent.getPackageName();
+ String providerName = null;
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
+ if (info != null) {
+ providerName = pm.getApplicationLabel(info).toString();
+ }
+ } catch (Exception e) {
+ providerName = packageName;
+ }
+ final String title = "AutoFill by '" + providerName + "'";
+ final String subTitle = "Tap notification to auto-fill top activity for user " + userId;
+
+ final Notification notification = new Notification.Builder(mContext)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setOngoing(true)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setLocalOnly(true)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setStyle(new Notification.BigTextStyle().bigText(subTitle))
+ .setContentIntent(pi)
+ .build();
+ NotificationManager.from(mContext).notify(userId, notification);
+ }
+
+ private void cancelNotificationLocked(int userId) {
+ if (DEBUG) Log.d(TAG, "cancelNotificationLocked(): " + userId);
+ NotificationManager.from(mContext).cancel(userId);
+ }
+
+ /////////////////////////////////////////
+ // End of temporary notification code. //
+ /////////////////////////////////////////
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
new file mode 100644
index 0000000..e409cb0
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.server.autofill.AutoFillManagerService.DEBUG;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.icu.text.DateFormat;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.IAutoFillService;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
+ * app's {@link IAutoFillService} implementation.
+ *
+ */
+final class AutoFillManagerServiceImpl {
+
+ private static final String TAG = "AutoFillManagerServiceImpl";
+
+ private final int mUserId;
+ private final int mUid;
+ private final ComponentName mComponent;
+ private final Context mContext;
+ private final IActivityManager mAm;
+ private final Object mLock;
+ private final AutoFillServiceInfo mInfo;
+ private final AutoFillManagerService mManagerService;
+
+ // TODO: improve its usage
+ // - set maximum number of entries
+ // - disable on low-memory devices.
+ private final List<String> mRequestHistory = new LinkedList<>();
+
+ @GuardedBy("mLock")
+ private final List<IBinder> mQueuedRequests = new LinkedList<>();
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ final String reason = intent.getStringExtra("reason");
+ if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
+ // TODO: close any pending UI like account selection (or remove this receiver)
+ }
+ }
+ };
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.d(TAG, "onServiceConnected():" + name);
+ synchronized (mLock) {
+ mService = IAutoFillService.Stub.asInterface(service);
+ try {
+ mService.onConnected();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception on service.onConnected(): " + e);
+ return;
+ }
+ if (!mQueuedRequests.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "queued requests:" + mQueuedRequests.size());
+ }
+ for (IBinder activityToken : mQueuedRequests) {
+ requestAutoFillLocked(activityToken, false);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(TAG, name + " disconnected");
+ synchronized (mLock) {
+ mService = null;
+ mManagerService.removeCachedServiceForUserLocked(mUserId);
+ }
+ }
+ };
+
+ @GuardedBy("mLock")
+ private IAutoFillService mService;
+ private boolean mBound;
+ private boolean mValid;
+
+ // Estimated time when the service will be evicted from the cache.
+ long mEstimateTimeOfDeath;
+
+ AutoFillManagerServiceImpl(AutoFillManagerService managerService, Context context, Object lock,
+ Handler handler, int userId, int uid,ComponentName component, long ttl) {
+ mManagerService = managerService;
+ mContext = context;
+ mLock = lock;
+ mUserId = userId;
+ mUid = uid;
+ mComponent = component;
+ mAm = ActivityManager.getService();
+ setLifeExpectancy(ttl);
+
+ final AutoFillServiceInfo info;
+ try {
+ info = new AutoFillServiceInfo(component, mUserId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Auto-fill service not found: " + component, e);
+ mInfo = null;
+ mValid = false;
+ return;
+ }
+ mInfo = info;
+ if (mInfo.getParseError() != null) {
+ Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError());
+ mValid = false;
+ return;
+ }
+
+ mValid = true;
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
+ }
+
+ void setLifeExpectancy(long ttl) {
+ mEstimateTimeOfDeath = SystemClock.uptimeMillis() + ttl;
+ }
+
+ void startLocked() {
+ if (DEBUG) Slog.d(TAG, "startLocked()");
+
+ final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE);
+ intent.setComponent(mComponent);
+ mBound = mContext.bindServiceAsUser(intent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUserId));
+
+ if (!mBound) {
+ Slog.w(TAG, "Failed binding to auto-fill service " + mComponent);
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
+ }
+
+ void requestAutoFill(IBinder activityToken) {
+ synchronized (mLock) {
+ if (!mBound) {
+ Slog.w(TAG, "requestAutoFill() failed because it's not bound to service");
+ return;
+ }
+ }
+
+ // TODO: activityToken should probably not be null, but we need to wait until the UI is
+ // triggering the call (for now it's trough 'adb shell cmd autofill request'
+ if (activityToken == null) {
+ // Let's get top activities from all visible stacks.
+
+ // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return
+ // activities for different users when a work profile app is displayed in another
+ // window (in a multi-window environment).
+ final List<IBinder> topActivities = LocalServices
+ .getService(ActivityManagerInternal.class).getTopVisibleActivities();
+ if (DEBUG)
+ Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+ if (topActivities.isEmpty()) {
+ Slog.w(TAG, "Could not get top activity");
+ return;
+ }
+ activityToken = topActivities.get(0);
+ }
+
+ final String historyItem =
+ DateFormat.getDateTimeInstance().format(new Date()) + " - " + activityToken;
+ synchronized (mLock) {
+ mRequestHistory.add(historyItem);
+ requestAutoFillLocked(activityToken, true);
+ }
+ }
+
+ private void requestAutoFillLocked(IBinder activityToken, boolean queueIfNecessary) {
+ if (mService == null) {
+ if (!queueIfNecessary) {
+ Slog.w(TAG, "requestAutoFillLocked(): service is null");
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "requestAutoFill(): service not set yet, queuing it");
+ mQueuedRequests.add(activityToken);
+ return;
+ }
+
+ /*
+ * TODO: apply security checks below:
+ * - checks if disabled by secure settings / device policy
+ * - log operation using noteOp()
+ * - check flags
+ * - display disclosure if needed
+ */
+ try {
+ // TODO: add MetricsLogger call
+ if (!mAm.requestAutoFillData(mService.getAssistReceiver(), null, activityToken)) {
+ // TODO: might need a way to warn user (perhaps a new method on AutoFillService).
+ Slog.w(TAG, "failed to request auto-fill data for " + activityToken);
+ }
+ } catch (RemoteException e) {
+ // Should happen, it's a local call.
+ }
+ }
+
+ void stopLocked() {
+ if (DEBUG) Slog.d(TAG, "stopLocked()");
+
+ // Sanity check.
+ if (mService == null) {
+ Log.w(TAG, "service already null on shutdown");
+ return;
+ }
+ try {
+ mService.onDisconnected();
+ } catch (RemoteException e) {
+ if (! (e instanceof DeadObjectException)) {
+ Slog.w(TAG, "Exception calling service.onDisconnected(): " + e);
+ }
+ } finally {
+ mService = null;
+ }
+
+ if (mBound) {
+ mContext.unbindService(mConnection);
+ mBound = false;
+ }
+ if (mValid) {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ }
+ }
+
+ void dumpLocked(String prefix, PrintWriter pw) {
+ if (!mValid) {
+ pw.print(" NOT VALID: ");
+ if (mInfo == null) {
+ pw.println("no info");
+ } else {
+ pw.println(mInfo.getParseError());
+ }
+ return;
+ }
+
+ pw.print(prefix); pw.print("mUserId="); pw.println(mUserId);
+ pw.print(prefix); pw.print("mUid="); pw.println(mUid);
+ pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
+ pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+ pw.print(prefix); pw.print("mService="); pw.println(mService);
+ pw.print(prefix); pw.print("mEstimateTimeOfDeath=");
+ TimeUtils.formatDuration(mEstimateTimeOfDeath, SystemClock.uptimeMillis(), pw);
+ pw.println();
+
+ if (DEBUG) {
+ // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
+ pw.print(prefix); pw.println("Service info:");
+ mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
+ }
+
+ if (mRequestHistory.isEmpty()) {
+ pw.print(prefix); pw.println("No history");
+ } else {
+ pw.print(prefix); pw.println("History:");
+ final String prefix2 = prefix + prefix;
+ for (int i = 0; i < mRequestHistory.size(); i++) {
+ pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mRequestHistory.get(i));
+ }
+ }
+ if (mQueuedRequests.isEmpty()) {
+ pw.print(prefix); pw.println("No queued requests");
+ } else {
+ pw.print(prefix); pw.println("Queued requests:");
+ final String prefix2 = prefix + prefix;
+ for (int i = 0; i < mQueuedRequests.size(); i++) {
+ pw.print(prefix2); pw.print(i); pw.print(": "); pw.println(mQueuedRequests.get(i));
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[AutoFillManagerServiceImpl: userId=" + mUserId + ", uid=" + mUid
+ + ", component=" + mComponent.flattenToShortString() + "]";
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
new file mode 100644
index 0000000..6406b8a
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import android.app.ActivityManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.service.autofill.IAutoFillManagerService;
+
+import java.io.PrintWriter;
+
+public final class AutoFillManagerServiceShellCommand extends ShellCommand {
+
+ private final IAutoFillManagerService.Stub mService;
+
+ public AutoFillManagerServiceShellCommand(IAutoFillManagerService.Stub service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch (cmd) {
+ case "request":
+ return requestAutoFill();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ pw.println("error: " + e);
+ }
+ return -1;
+ }
+
+ @Override
+ public void onHelp() {
+ try (final PrintWriter pw = getOutPrintWriter();) {
+ pw.println("AutoFill Service (autofill) commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" request [--user USER_ID]");
+ pw.println(" Request auto-fill on the top activity. ");
+ pw.println("");
+ }
+ }
+
+ private int requestAutoFill() throws RemoteException {
+ final int userId = getUserIdFromArgs();
+ mService.requestAutoFill(userId, null);
+ return 0;
+ }
+
+ private int getUserIdFromArgs() {
+ if ("--user".equals(getNextArg())) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ }
+ return ActivityManager.getCurrentUser();
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6375e9a..8151c8a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -18,7 +18,7 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.ApplicationThreadConstants;
@@ -80,7 +80,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.Environment.UserEnvironment;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.system.ErrnoException;
@@ -268,7 +268,7 @@
private IActivityManager mActivityManager;
private PowerManager mPowerManager;
private AlarmManager mAlarmManager;
- private IMountService mMountService;
+ private IStorageManager mStorageManager;
IBackupManager mBackupManagerBinder;
boolean mEnabled; // access to this is synchronized on 'this'
@@ -1075,11 +1075,11 @@
mContext = context;
mPackageManager = context.getPackageManager();
mPackageManagerBinder = AppGlobals.getPackageManager();
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
@@ -3982,14 +3982,14 @@
boolean deviceIsEncrypted() {
try {
- return mMountService.getEncryptionState()
+ return mStorageManager.getEncryptionState()
!= StorageManager.ENCRYPTION_STATE_NONE
- && mMountService.getPasswordType()
+ && mStorageManager.getPasswordType()
!= StorageManager.CRYPT_TYPE_DEFAULT;
} catch (Exception e) {
- // If we can't talk to the mount service we have a serious problem; fail
+ // If we can't talk to the storagemanager service we have a serious problem; fail
// "secure" i.e. assuming that the device is encrypted.
- Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
+ Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
return true;
}
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 8e01e9e..581aa05d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -505,7 +504,7 @@
for (int i = alarms.size()-1; i >= 0; i--) {
Alarm alarm = alarms.get(i);
try {
- if (alarm.uid == uid && ActivityManagerNative.getDefault().getAppStartMode(
+ if (alarm.uid == uid && ActivityManager.getService().getAppStartMode(
uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) {
alarms.remove(i);
didRemove = true;
@@ -937,8 +936,8 @@
}
try {
- ActivityManagerNative.getDefault().registerUidObserver(new UidObserver(),
- ActivityManager.UID_OBSERVER_IDLE, null);
+ ActivityManager.getService().registerUidObserver(new UidObserver(),
+ ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN, null);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
@@ -1090,7 +1089,7 @@
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
callingUid, callingPackage);
try {
- if (ActivityManagerNative.getDefault().getAppStartMode(callingUid, callingPackage)
+ if (ActivityManager.getService().getAppStartMode(callingUid, callingPackage)
== ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
+ " -- package not allowed to start");
@@ -1940,13 +1939,9 @@
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
- try {
- if (a.uid == uid && ActivityManagerNative.getDefault().getAppStartMode(
- uid, a.packageName) == ActivityManager.APP_START_MODE_DISABLED) {
- // Don't set didRemove, since this doesn't impact the scheduled alarms.
- mPendingWhileIdleAlarms.remove(i);
- }
- } catch (RemoteException e) {
+ if (a.uid == uid) {
+ // Don't set didRemove, since this doesn't impact the scheduled alarms.
+ mPendingWhileIdleAlarms.remove(i);
}
}
@@ -2418,11 +2413,11 @@
if (RECORD_ALARMS_IN_HISTORY) {
if (alarm.workSource != null && alarm.workSource.size() > 0) {
for (int wi=0; wi<alarm.workSource.size(); wi++) {
- ActivityManagerNative.noteAlarmStart(
+ ActivityManager.noteAlarmStart(
alarm.operation, alarm.workSource.get(wi), alarm.statsTag);
}
} else {
- ActivityManagerNative.noteAlarmStart(
+ ActivityManager.noteAlarmStart(
alarm.operation, alarm.uid, alarm.statsTag);
}
}
@@ -2586,7 +2581,7 @@
final int uid = (knownUid >= 0)
? knownUid
- : ActivityManagerNative.getDefault().getUidForIntentSender(pi.getTarget());
+ : ActivityManager.getService().getUidForIntentSender(pi.getTarget());
if (uid >= 0) {
mWakeLock.setWorkSource(new WorkSource(uid));
return;
@@ -2807,15 +2802,22 @@
@Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
}
- @Override public void onUidGone(int uid) throws RemoteException {
+ @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
+ if (disabled) {
+ synchronized (mLock) {
+ removeForStoppedLocked(uid);
+ }
+ }
}
@Override public void onUidActive(int uid) throws RemoteException {
}
- @Override public void onUidIdle(int uid) throws RemoteException {
- synchronized (mLock) {
- removeForStoppedLocked(uid);
+ @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+ if (disabled) {
+ synchronized (mLock) {
+ removeForStoppedLocked(uid);
+ }
}
}
};
@@ -2878,11 +2880,11 @@
if (RECORD_ALARMS_IN_HISTORY) {
if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
- ActivityManagerNative.noteAlarmFinish(
+ ActivityManager.noteAlarmFinish(
inflight.mPendingIntent, inflight.mWorkSource.get(wi), inflight.mTag);
}
} else {
- ActivityManagerNative.noteAlarmFinish(
+ ActivityManager.noteAlarmFinish(
inflight.mPendingIntent, inflight.mUid, inflight.mTag);
}
}
@@ -3083,13 +3085,13 @@
if (alarm.workSource != null && alarm.workSource.size() > 0) {
for (int wi=0; wi<alarm.workSource.size(); wi++) {
final String wsName = alarm.workSource.getName(wi);
- ActivityManagerNative.noteWakeupAlarm(
+ ActivityManager.noteWakeupAlarm(
alarm.operation, alarm.workSource.get(wi),
(wsName != null) ? wsName : alarm.packageName,
alarm.statsTag);
}
} else {
- ActivityManagerNative.noteWakeupAlarm(
+ ActivityManager.noteWakeupAlarm(
alarm.operation, alarm.uid, alarm.packageName, alarm.statsTag);
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 7c2eea3f..570843e 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -54,7 +54,7 @@
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.UserHandle;
-import android.os.storage.MountServiceInternal;
+import android.os.storage.StorageManagerInternal;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -294,10 +294,10 @@
}
}
- MountServiceInternal mountServiceInternal = LocalServices.getService(
- MountServiceInternal.class);
- mountServiceInternal.addExternalStoragePolicy(
- new MountServiceInternal.ExternalStorageMountPolicy() {
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ storageManagerInternal.addExternalStoragePolicy(
+ new StorageManagerInternal.ExternalStorageMountPolicy() {
@Override
public int getMountMode(int uid, String packageName) {
if (Process.isIsolated(uid)) {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index b88a45e..573ad63 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -28,7 +28,7 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -557,7 +557,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
});
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 6456048..f7068cf 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -59,6 +59,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.Map;
@@ -118,7 +119,6 @@
private static final int SERVICE_IBLUETOOTHGATT = 2;
private final Context mContext;
- private static int mBleAppCount = 0;
// Locks are not provided for mName and mAddress.
// They are accessed in handler or broadcast receiver, same thread context.
@@ -212,10 +212,7 @@
if (isAirplaneModeOn()) {
// Clear registered LE apps to force shut-off
- synchronized (this) {
- mBleAppCount = 0;
- mBleApps.clear();
- }
+ clearBleApps();
if (st == BluetoothAdapter.STATE_BLE_ON) {
//if state is BLE_ON make sure you trigger disableBLE part
try {
@@ -460,28 +457,28 @@
class ClientDeathRecipient implements IBinder.DeathRecipient {
public void binderDied() {
if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
- if (mBleAppCount > 0) --mBleAppCount;
-
- if (mBleAppCount == 0) {
- if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null &&
- mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
- mEnable = false;
- mBluetooth.onBrEdrDown();
- }
- } catch (RemoteException e) {
- Slog.e(TAG,"Unable to call onBrEdrDown", e);
- } finally {
- mBluetoothLock.readLock().unlock();
+ if (isBleAppPresent()) {
+ // Nothing to do, another app is here.
+ return;
+ }
+ if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null &&
+ mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ mEnable = false;
+ mBluetooth.onBrEdrDown();
}
+ } catch (RemoteException e) {
+ Slog.e(TAG,"Unable to call onBrEdrDown", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
}
}
}
/** Internal death rec list */
- Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
+ Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
@Override
public boolean isBleScanAlwaysAvailable() {
@@ -501,17 +498,20 @@
ContentObserver contentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
- if (!isBleScanAlwaysAvailable()) {
- disableBleScanMode();
- clearBleApps();
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) mBluetooth.onBrEdrDown();
- } catch (RemoteException e) {
- Slog.e(TAG, "error when disabling bluetooth", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
+ if (isBleScanAlwaysAvailable()) {
+ // Nothing to do
+ return;
+ }
+ // BLE scan is not available.
+ disableBleScanMode();
+ clearBleApps();
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null) mBluetooth.onBrEdrDown();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error when disabling bluetooth", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
}
}
};
@@ -547,9 +547,6 @@
throw new IllegalArgumentException("Wake lock is already dead.");
}
mBleApps.put(token, deathRec);
- synchronized (this) {
- ++mBleAppCount;
- }
if (DBG) Slog.d(TAG, "Registered for death Notification");
}
@@ -559,31 +556,26 @@
// Unregister death recipient as the app goes away.
token.unlinkToDeath(r, 0);
mBleApps.remove(token);
- synchronized (this) {
- if (mBleAppCount > 0) --mBleAppCount;
- }
if (DBG) Slog.d(TAG, "Unregistered for death Notification");
}
}
- if (DBG) Slog.d(TAG, "Updated BleAppCount" + mBleAppCount);
- if (mBleAppCount == 0 && mEnable) {
+ int appCount = mBleApps.size();
+ if (DBG) Slog.d(TAG, appCount + " registered Ble Apps");
+ if (appCount == 0 && mEnable) {
disableBleScanMode();
}
- return mBleAppCount;
+ return appCount;
}
// Clear all apps using BLE scan only mode.
private void clearBleApps() {
- synchronized (this) {
- mBleApps.clear();
- mBleAppCount = 0;
- }
+ mBleApps.clear();
}
/** @hide*/
public boolean isBleAppPresent() {
- if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
- return (mBleAppCount > 0);
+ if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
+ return mBleApps.size() > 0;
}
/**
@@ -1364,7 +1356,8 @@
try {
mBluetoothLock.writeLock().lock();
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
+ mBluetoothGatt = IBluetoothGatt.Stub
+ .asInterface(Binder.allowBlocking(service));
onBluetoothGattServiceUp();
break;
} // else must be SERVICE_IBLUETOOTH
@@ -1374,7 +1367,7 @@
mBinding = false;
mBluetoothBinder = service;
- mBluetooth = IBluetooth.Stub.asInterface(service);
+ mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));
if (!isNameAndAddressSet()) {
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
@@ -1448,12 +1441,12 @@
if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
(newState == BluetoothAdapter.STATE_OFF) &&
(mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError();
+ recoverBluetoothServiceFromError(false);
}
if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
(newState == BluetoothAdapter.STATE_BLE_ON) &&
(mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError();
+ recoverBluetoothServiceFromError(true);
}
// If we tried to enable BT while BT was in the process of shutting down,
// wait for the BT process to fully tear down and then force a restart
@@ -1869,7 +1862,7 @@
quietMode ? 1 : 0, 0));
}
- private void recoverBluetoothServiceFromError() {
+ private void recoverBluetoothServiceFromError(boolean clearBle) {
Slog.e(TAG,"recoverBluetoothServiceFromError");
try {
mBluetoothLock.readLock().lock();
@@ -1907,6 +1900,10 @@
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
+ if (clearBle) {
+ clearBleApps();
+ }
+
mEnable = false;
if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 466633a..07322fc 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -17,7 +17,7 @@
package com.android.server;
import android.Manifest;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -1572,7 +1572,7 @@
Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
"No permission to change device idle whitelist");
final int callingUid = Binder.getCallingUid();
- userId = ActivityManagerNative.getDefault().handleIncomingUser(
+ userId = ActivityManager.getService().handleIncomingUser(
Binder.getCallingPid(),
callingUid,
userId,
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 74ff41c..eb2cd0b 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -248,7 +248,7 @@
51501 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5)
# ---------------------------
-# MountService.java
+# StorageManagerService.java
# ---------------------------
2755 fstrim_start (time|2|3)
2756 fstrim_finish (time|2|3)
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 553cb07..830a6ed 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -40,7 +40,7 @@
import android.view.KeyEvent;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.statusbar.StatusBarManagerInternal;
/**
diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/InputContentUriTokenHandler.java
index 3f4972b..57cdc94 100644
--- a/services/core/java/com/android/server/InputContentUriTokenHandler.java
+++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
@@ -64,7 +64,7 @@
}
try {
- mPermissionOwnerToken = ActivityManagerNative.getDefault()
+ mPermissionOwnerToken = ActivityManager.getService()
.newUriPermissionOwner("InputContentUriTokenHandler");
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -78,7 +78,7 @@
long origId = Binder.clearCallingIdentity();
try {
try {
- ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+ ActivityManager.getService().grantUriPermissionFromOwner(
permissionOwner, mSourceUid, mTargetPackage, mUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId);
} catch (RemoteException e) {
@@ -96,7 +96,7 @@
return;
}
try {
- ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
+ ActivityManager.getService().revokeUriPermissionFromOwner(
mPermissionOwnerToken, mUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 2698f95..3dfbdc3 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -29,6 +29,7 @@
import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -48,8 +49,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -59,6 +60,7 @@
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -905,7 +907,7 @@
mNotificationShown = false;
int userId = 0;
try {
- userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ userId = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
}
@@ -3968,10 +3970,22 @@
+ mCurAttribute.packageName + " packageName=" + packageName);
return null;
}
+ // This user ID can never bee spoofed.
final int imeUserId = UserHandle.getUserId(uid);
+ // This user ID can never bee spoofed.
final int appUserId = UserHandle.getUserId(mCurClient.uid);
- return new InputContentUriTokenHandler(contentUri, uid, packageName, imeUserId,
- appUserId);
+ // This user ID may be invalid if "contentUri" embedded an invalid user ID.
+ final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
+ imeUserId);
+ final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
+ // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
+ // actually has the right to grant a read permission for "contentUriWithoutUserId" that
+ // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
+ // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
+ // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
+ // actually allowed to "uid", which is guaranteed to be the IME's one.
+ return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
+ packageName, contentUriOwnerUserId, appUserId);
}
}
@@ -4041,9 +4055,9 @@
if (client != null) {
pw.flush();
try {
- client.client.asBinder().dump(fd, args);
- } catch (RemoteException e) {
- p.println("Input method client dead: " + e);
+ TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ p.println("Failed to dump input method client: " + e);
}
} else {
p.println("No input method client.");
@@ -4057,9 +4071,9 @@
p.println(" ");
pw.flush();
try {
- focusedWindowClient.client.asBinder().dump(fd, args);
- } catch (RemoteException e) {
- p.println("Input method client in focused window dead: " + e);
+ TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ p.println("Failed to dump input method client in focused window: " + e);
}
}
@@ -4067,9 +4081,9 @@
if (method != null) {
pw.flush();
try {
- method.asBinder().dump(fd, args);
- } catch (RemoteException e) {
- p.println("Input method service dead: " + e);
+ TransferPipe.dumpAsync(method.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ p.println("Failed to dump input method service: " + e);
}
} else {
p.println("No input method service.");
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index a2207b2..6701431 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -16,7 +16,7 @@
package com.android.server;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -49,7 +49,9 @@
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
-import android.os.storage.IMountService;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -79,6 +81,7 @@
import libcore.util.HexEncoding;
import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -810,7 +813,7 @@
};
try {
- ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener);
+ ActivityManager.getService().unlockUser(userId, token, secret, listener);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -1157,10 +1160,10 @@
private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
throws RemoteException {
final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
- final IMountService mountService = getMountService();
+ final IStorageManager storageManager = getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
- mountService.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
+ storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -1168,10 +1171,10 @@
private void fixateNewestUserKeyAuth(int userId)
throws RemoteException {
- final IMountService mountService = getMountService();
+ final IStorageManager storageManager = getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
- mountService.fixateNewestUserKeyAuth(userId);
+ storageManager.fixateNewestUserKeyAuth(userId);
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -1485,7 +1488,7 @@
// we should, within the first minute of decrypting the phone if this
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
- final IMountService service = getMountService();
+ final IStorageManager service = getStorageManager();
String password;
long identity = Binder.clearCallingIdentity();
try {
@@ -1585,6 +1588,31 @@
return mStrongAuthTracker.getStrongAuthForUser(userId);
}
+ private boolean isCallerShell() {
+ final int callingUid = Binder.getCallingUid();
+ return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+ }
+
+ private void enforceShell() {
+ if (!isCallerShell()) {
+ throw new SecurityException("Caller must be shell");
+ }
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+ throws RemoteException {
+ enforceShell();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -1623,10 +1651,10 @@
Secure.LOCK_SCREEN_OWNER_INFO
};
- private IMountService getMountService() {
+ private IStorageManager getStorageManager() {
final IBinder service = ServiceManager.getService("mount");
if (service != null) {
- return IMountService.Stub.asInterface(service);
+ return IStorageManager.Stub.asInterface(service);
}
return null;
}
diff --git a/services/core/java/com/android/server/LockSettingsShellCommand.java b/services/core/java/com/android/server/LockSettingsShellCommand.java
new file mode 100644
index 0000000..f72663a
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsShellCommand.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static com.android.internal.widget.LockPatternUtils.stringToPattern;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+
+class LockSettingsShellCommand extends ShellCommand {
+
+ private static final String COMMAND_SET_PATTERN = "set-pattern";
+ private static final String COMMAND_SET_PIN = "set-pin";
+ private static final String COMMAND_SET_PASSWORD = "set-password";
+ private static final String COMMAND_CLEAR = "clear";
+
+ private int mCurrentUserId;
+ private final LockPatternUtils mLockPatternUtils;
+ private final Context mContext;
+ private String mOld = "";
+ private String mNew = "";
+
+ LockSettingsShellCommand(Context context, LockPatternUtils lockPatternUtils) {
+ mContext = context;
+ mLockPatternUtils = lockPatternUtils;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ try {
+ mCurrentUserId = ActivityManager.getService().getCurrentUser().id;
+
+ parseArgs();
+ if (!checkCredential()) {
+ return -1;
+ }
+ switch (cmd) {
+ case COMMAND_SET_PATTERN:
+ runSetPattern();
+ break;
+ case COMMAND_SET_PASSWORD:
+ runSetPassword();
+ break;
+ case COMMAND_SET_PIN:
+ runSetPin();
+ break;
+ case COMMAND_CLEAR:
+ runClear();
+ break;
+ default:
+ getErrPrintWriter().println("Unknown command: " + cmd);
+ break;
+ }
+ return 0;
+ } catch (Exception e) {
+ getErrPrintWriter().println("Error while executing command: " + e);
+ return -1;
+ }
+ }
+
+ @Override
+ public void onHelp() {
+ }
+
+ private void parseArgs() {
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if ("--old".equals(opt)) {
+ mOld = getNextArgRequired();
+ } else {
+ getErrPrintWriter().println("Unknown option: " + opt);
+ throw new IllegalArgumentException();
+ }
+ }
+ mNew = getNextArg();
+ }
+
+ private void runSetPattern() throws RemoteException {
+ mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
+ getOutPrintWriter().println("Pattern set to '" + mNew + "'");
+ }
+
+ private void runSetPassword() throws RemoteException {
+ mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
+ getOutPrintWriter().println("Password set to '" + mNew + "'");
+ }
+
+ private void runSetPin() throws RemoteException {
+ mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
+ getOutPrintWriter().println("Pin set to '" + mNew + "'");
+ }
+
+ private void runClear() throws RemoteException {
+ mLockPatternUtils.clearLock(mCurrentUserId);
+ getOutPrintWriter().println("Lock credential cleared");
+ }
+
+ private boolean checkCredential() throws RemoteException, RequestThrottledException {
+ final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId);
+ final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId);
+ if (havePassword || havePattern) {
+ boolean result;
+ if (havePassword) {
+ result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
+ } else {
+ result = mLockPatternUtils.checkPattern(stringToPattern(mOld),
+ mCurrentUserId);
+ }
+ if (result) {
+ return true;
+ } else {
+ getOutPrintWriter().println("Old password '" + mOld + "' didn't match");
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 33f9234..0414b47 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -92,7 +92,7 @@
public void onServiceConnected(ComponentName name, IBinder service) {
Slog.i(TAG, "MmsService connected");
synchronized (MmsServiceBroker.this) {
- mService = IMms.Stub.asInterface(service);
+ mService = IMms.Stub.asInterface(Binder.allowBlocking(service));
MmsServiceBroker.this.notifyAll();
}
}
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index e0b2307..d8bd0bb 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -18,7 +18,7 @@
import java.util.Calendar;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -59,7 +59,7 @@
// is really more than just mount, some day it should be renamed to be system
// idleer).
try {
- ActivityManagerNative.getDefault().performIdleMaintenance();
+ ActivityManager.getService().performIdleMaintenance();
} catch (RemoteException e) {
}
// The mount service will run an fstrim operation asynchronously
@@ -67,7 +67,7 @@
// that lets us cleanly end our idle timeslice. It's safe to call
// finishIdle() from any thread.
mJobParams = params;
- MountService ms = MountService.sSelf;
+ StorageManagerService ms = StorageManagerService.sSelf;
if (ms != null) {
synchronized (mFinishCallback) {
mStarted = true;
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index e64aa16..5654096 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -46,7 +46,7 @@
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.annotation.NonNull;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -958,7 +958,7 @@
final int uid = Integer.parseInt(cooked[1]);
final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
try {
- ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket);
+ ActivityManager.getService().notifyCleartextNetwork(uid, firstPacket);
} catch (RemoteException ignored) {
}
break;
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 83d6344..f5cda0a 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -42,8 +42,10 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.TransferPipe;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -418,12 +420,9 @@
for (INetworkScoreCache scoreCache : getScoreCaches()) {
try {
- scoreCache.asBinder().dump(fd, args);
- } catch (RemoteException e) {
- writer.println("Unable to dump score cache");
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Unable to dump score cache", e);
- }
+ TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ writer.println("Failed to dump score cache: " + e);
}
}
if (mServiceConnection != null) {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 356ccb3..fa5a52c 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -63,7 +63,7 @@
private BinderService mBinderService;
- private final long MAX_CAMERA_PIN_SIZE = 50 * (1 << 20); //50MB max
+ private final long MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
private PinnerHandler mPinnerHandler = null;
@@ -192,6 +192,9 @@
if (isResolverActivity(cameraResolveInfo.activityInfo))
{
+ if (DEBUG) {
+ Slog.v(TAG, "cameraIntent returned resolverActivity");
+ }
return null;
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/StorageManagerService.java
similarity index 97%
rename from services/core/java/com/android/server/MountService.java
rename to services/core/java/com/android/server/StorageManagerService.java
index 8b7b6a0..11fabb4 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -31,7 +31,6 @@
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
@@ -69,11 +68,11 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.DiskInfo;
-import android.os.storage.IMountService;
-import android.os.storage.IMountServiceListener;
-import android.os.storage.IMountShutdownObserver;
+import android.os.storage.IStorageEventListener;
+import android.os.storage.IStorageShutdownObserver;
import android.os.storage.IObbActionListener;
-import android.os.storage.MountServiceInternal;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManagerInternal;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
@@ -150,14 +149,14 @@
* watch for and manage dynamically added storage, such as SD cards and USB mass
* storage. Also decides how storage should be presented to users on the device.
*/
-class MountService extends IMountService.Stub
+class StorageManagerService extends IStorageManager.Stub
implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
// Static direct instance pointer for the tightly-coupled idle service to use
- static MountService sSelf = null;
+ static StorageManagerService sSelf = null;
public static class Lifecycle extends SystemService {
- private MountService mMountService;
+ private StorageManagerService mStorageManagerService;
public Lifecycle(Context context) {
super(context);
@@ -165,33 +164,33 @@
@Override
public void onStart() {
- mMountService = new MountService(getContext());
- publishBinderService("mount", mMountService);
- mMountService.start();
+ mStorageManagerService = new StorageManagerService(getContext());
+ publishBinderService("mount", mStorageManagerService);
+ mStorageManagerService.start();
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mMountService.systemReady();
+ mStorageManagerService.systemReady();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
- mMountService.bootCompleted();
+ mStorageManagerService.bootCompleted();
}
}
@Override
public void onSwitchUser(int userHandle) {
- mMountService.mCurrentUserId = userHandle;
+ mStorageManagerService.mCurrentUserId = userHandle;
}
@Override
public void onUnlockUser(int userHandle) {
- mMountService.onUnlockUser(userHandle);
+ mStorageManagerService.onUnlockUser(userHandle);
}
@Override
public void onCleanupUser(int userHandle) {
- mMountService.onCleanupUser(userHandle);
+ mStorageManagerService.onCleanupUser(userHandle);
}
}
@@ -210,7 +209,7 @@
*/
private static final boolean EMULATE_FBE_SUPPORTED = true;
- private static final String TAG = "MountService";
+ private static final String TAG = "StorageManagerService";
private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
private static final String TAG_STORAGE_TRIM = "storage_trim";
@@ -501,7 +500,8 @@
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
// Not guarded by a lock.
- private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
+ private final StorageManagerInternalImpl mStorageManagerInternal
+ = new StorageManagerInternalImpl();
class ObbState implements IBinder.DeathRecipient {
public ObbState(String rawPath, String canonicalPath, int callingUid,
@@ -610,8 +610,8 @@
private static final int H_PARTITION_FORGET = 9;
private static final int H_RESET = 10;
- class MountServiceHandler extends Handler {
- public MountServiceHandler(Looper looper) {
+ class StorageManagerServiceHandler extends Handler {
+ public StorageManagerServiceHandler(Looper looper) {
super(looper);
}
@@ -662,7 +662,7 @@
break;
}
case H_SHUTDOWN: {
- final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
+ final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
boolean success = false;
try {
success = mConnector.execute("volume", "shutdown").isClassOk();
@@ -836,7 +836,7 @@
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
user.id);
if (provider != null) {
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
try {
am.killApplication(provider.applicationInfo.packageName,
UserHandle.getAppId(provider.applicationInfo.uid),
@@ -1029,7 +1029,7 @@
Configuration config = new Configuration();
config.setLocale(locale);
try {
- ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
+ ActivityManager.getService().updatePersistentConfiguration(config);
} catch (RemoteException e) {
Slog.e(TAG, "Error setting system locale from mount service", e);
}
@@ -1482,11 +1482,11 @@
}
/**
- * Constructs a new MountService instance
+ * Constructs a new StorageManagerService instance
*
* @param context Binder context for this service
*/
- public MountService(Context context) {
+ public StorageManagerService(Context context) {
sSelf = this;
mContext = context;
@@ -1498,9 +1498,9 @@
HandlerThread hthread = new HandlerThread(TAG);
hthread.start();
- mHandler = new MountServiceHandler(hthread.getLooper());
+ mHandler = new StorageManagerServiceHandler(hthread.getLooper());
- // Add OBB Action Handler to MountService thread.
+ // Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
// Initialize the last-fstrim tracking if necessary
@@ -1526,7 +1526,7 @@
readSettingsLocked();
}
- LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
+ LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
/*
* Create the connection to vold with a maximum queue of twice the
@@ -1686,17 +1686,17 @@
*/
@Override
- public void registerListener(IMountServiceListener listener) {
+ public void registerListener(IStorageEventListener listener) {
mCallbacks.register(listener);
}
@Override
- public void unregisterListener(IMountServiceListener listener) {
+ public void unregisterListener(IStorageEventListener listener) {
mCallbacks.unregister(listener);
}
@Override
- public void shutdown(final IMountShutdownObserver observer) {
+ public void shutdown(final IStorageShutdownObserver observer) {
enforcePermission(android.Manifest.permission.SHUTDOWN);
Slog.i(TAG, "Shutting down");
@@ -3046,7 +3046,7 @@
final long token = Binder.clearCallingIdentity();
try {
userKeyUnlocked = isUserKeyUnlocked(userId);
- storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
+ storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -3163,7 +3163,7 @@
for (final ObbState o : obbStates) {
if (o.rawPath.equals(obbState.rawPath)) {
throw new IllegalStateException("Attempt to add ObbState twice. "
- + "This indicates an error in the MountService logic.");
+ + "This indicates an error in the StorageManagerService logic.");
}
}
}
@@ -3425,7 +3425,7 @@
try {
mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
} catch (RemoteException e) {
- Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
+ Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
}
}
}
@@ -3615,18 +3615,18 @@
private static final int MSG_DISK_SCANNED = 5;
private static final int MSG_DISK_DESTROYED = 6;
- private final RemoteCallbackList<IMountServiceListener>
+ private final RemoteCallbackList<IStorageEventListener>
mCallbacks = new RemoteCallbackList<>();
public Callbacks(Looper looper) {
super(looper);
}
- public void register(IMountServiceListener callback) {
+ public void register(IStorageEventListener callback) {
mCallbacks.register(callback);
}
- public void unregister(IMountServiceListener callback) {
+ public void unregister(IStorageEventListener callback) {
mCallbacks.unregister(callback);
}
@@ -3635,7 +3635,7 @@
final SomeArgs args = (SomeArgs) msg.obj;
final int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
- final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
+ final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
try {
invokeCallback(callback, msg.what, args);
} catch (RemoteException ignored) {
@@ -3645,7 +3645,7 @@
args.recycle();
}
- private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
+ private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
throws RemoteException {
switch (what) {
case MSG_STORAGE_STATE_CHANGED: {
@@ -3830,7 +3830,7 @@
}
}
- private final class MountServiceInternalImpl extends MountServiceInternal {
+ private final class StorageManagerInternalImpl extends StorageManagerInternal {
// Not guarded by a lock.
private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
new CopyOnWriteArrayList<>();
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 4f02a23..cbd7be7 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -30,7 +30,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -159,7 +159,7 @@
int userId = UserHandle.USER_SYSTEM;
try {
- userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ userId = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 2825cf9..6ea6fb7 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IUiModeManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -39,19 +38,24 @@
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.Sandman;
import android.util.Slog;
+import android.view.WindowManagerInternal;
+import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
+import com.android.server.power.ShutdownThread;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import com.android.server.wm.WindowManagerService;
final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
@@ -297,6 +301,30 @@
}
@Override
+ public void setTheme(String theme) {
+ if (getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_THEME_OVERLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission");
+ return;
+ }
+ SystemProperties.set("persist.vendor.overlay.theme", theme);
+ mHandler.post(() -> ShutdownThread.reboot(getContext(),
+ PowerManager.SHUTDOWN_USER_REQUESTED, false));
+ }
+
+ @Override
+ public String getTheme() {
+ if (getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_THEME_OVERLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "setTheme requires MODIFY_THEME_OVERLAY permission");
+ return null;
+ }
+ return SystemProperties.get("persist.vendor.overlay.theme");
+ }
+
+ @Override
public int getNightMode() {
synchronized (mLock) {
return mNightMode;
@@ -446,7 +474,7 @@
mSetUiMode = mConfiguration.uiMode;
try {
- ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+ ActivityManager.getService().updateConfiguration(mConfiguration);
} catch (RemoteException e) {
Slog.w(TAG, "Failure communicating with activity manager", e);
}
@@ -608,7 +636,7 @@
Intent homeIntent = buildHomeIntent(category);
if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
- int result = ActivityManagerNative.getDefault().startActivityWithConfig(
+ int result = ActivityManager.getService().startActivityWithConfig(
null, null, homeIntent, null, null, null, 0, 0,
mConfiguration, null, UserHandle.USER_CURRENT);
if (result >= ActivityManager.START_SUCCESS) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 7802576..b5fecfb 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -34,7 +34,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -3999,7 +3998,7 @@
public AccountAndUser[] getRunningAccounts() {
final int[] runningUserIds;
try {
- runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ runningUserIds = ActivityManager.getService().getRunningUserIds();
} catch (RemoteException e) {
// Running in system_server; should never happen
throw new RuntimeException(e);
@@ -4940,7 +4939,7 @@
private int handleIncomingUser(int userId) {
try {
- return ActivityManagerNative.getDefault().handleIncomingUser(
+ return ActivityManager.getService().handleIncomingUser(
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
} catch (RemoteException re) {
// Shouldn't happen, local.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index dc4a52d..136e02c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -348,7 +348,7 @@
// Before going further -- if this app is not allowed to run in the
// background, then at this point we aren't going to let it period.
final int allowed = mAm.checkAllowBackgroundLocked(
- r.appInfo.uid, r.packageName, callingPid, true);
+ r.appInfo.uid, r.packageName, callingPid, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
@@ -594,7 +594,8 @@
for (int i=services.mServicesByName.size()-1; i>=0; i--) {
ServiceRecord service = services.mServicesByName.valueAt(i);
if (service.appInfo.uid == uid && service.startRequested) {
- if (mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
+ if (service.appInfo.isEphemeralApp() ||
+ mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, service.packageName) != AppOpsManager.MODE_ALLOWED) {
if (stopping == null) {
stopping = new ArrayList<>();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2d6832d..77d36f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,10 +21,8 @@
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.app.WaitResult;
+import android.graphics.PointF;
import android.os.IDeviceIdentifiersPolicyService;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.DisplayInfo;
import com.android.internal.telephony.TelephonyIntents;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -80,7 +78,6 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskThumbnailInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
@@ -199,8 +196,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.storage.IMountService;
-import android.os.storage.MountServiceInternal;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
@@ -221,6 +218,7 @@
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
import android.view.Gravity;
@@ -293,10 +291,8 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
-import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.provider.Settings.System.FONT_SCALE;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -1363,7 +1359,6 @@
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
boolean mSupportsMultiWindow;
boolean mSupportsFreeformWindowManagement;
@@ -1398,6 +1393,27 @@
boolean foregroundActivities;
}
+ static final class UidObserverRegistration {
+ final int uid;
+ final String pkg;
+ final int which;
+ final int cutpoint;
+
+ final SparseIntArray lastProcStates;
+
+ UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
+ uid = _uid;
+ pkg = _pkg;
+ which = _which;
+ cutpoint = _cutpoint;
+ if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+ lastProcStates = new SparseIntArray();
+ } else {
+ lastProcStates = null;
+ }
+ }
+ }
+
final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
@@ -1557,6 +1573,10 @@
int mThumbnailHeight;
float mFullscreenThumbnailScale;
+ /** The aspect ratio bounds of the PIP. */
+ float mMinPipAspectRatio;
+ float mMaxPipAspectRatio;
+
final ServiceThread mHandlerThread;
final MainHandler mHandler;
final UiHandler mUiHandler;
@@ -2077,9 +2097,9 @@
try {
Locale l = (Locale) msg.obj;
IBinder service = ServiceManager.getService("mount");
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
- mountService.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
+ storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
} catch (RemoteException e) {
Log.e(TAG, "Error storing locale for decryption UI", e);
}
@@ -2714,7 +2734,8 @@
for (int i=0; i<N; i++) {
Parcel data2 = Parcel.obtain();
try {
- procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, 0);
+ procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null,
+ Binder.FLAG_ONEWAY);
} catch (RemoteException e) {
}
data2.recycle();
@@ -3578,9 +3599,9 @@
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
- MountServiceInternal mountServiceInternal = LocalServices.getService(
- MountServiceInternal.class);
- mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
@@ -4105,7 +4126,8 @@
while (i > 0) {
i--;
final IUidObserver observer = mUidObservers.getBroadcastItem(i);
- final int which = (Integer)mUidObservers.getBroadcastCookie(i);
+ final UidObserverRegistration reg = (UidObserverRegistration)
+ mUidObservers.getBroadcastCookie(i);
if (observer != null) {
try {
for (int j=0; j<N; j++) {
@@ -4122,10 +4144,10 @@
}
if (change == UidRecord.CHANGE_IDLE
|| change == UidRecord.CHANGE_GONE_IDLE) {
- if ((which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"UID idle uid=" + item.uid);
- observer.onUidIdle(item.uid);
+ observer.onUidIdle(item.uid, item.ephemeral);
}
if (VALIDATE_UID_STATES && i == 0) {
if (validateUid != null) {
@@ -4133,7 +4155,7 @@
}
}
} else if (change == UidRecord.CHANGE_ACTIVE) {
- if ((which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"UID active uid=" + item.uid);
observer.onUidActive(item.uid);
@@ -4144,10 +4166,13 @@
}
if (change == UidRecord.CHANGE_GONE
|| change == UidRecord.CHANGE_GONE_IDLE) {
- if ((which & ActivityManager.UID_OBSERVER_GONE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"UID gone uid=" + item.uid);
- observer.onUidGone(item.uid);
+ observer.onUidGone(item.uid, item.ephemeral);
+ }
+ if (reg.lastProcStates != null) {
+ reg.lastProcStates.delete(item.uid);
}
if (VALIDATE_UID_STATES && i == 0) {
if (validateUid != null) {
@@ -4155,11 +4180,29 @@
}
}
} else {
- if ((which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"UID CHANGED uid=" + item.uid
+ ": " + item.processState);
- observer.onUidStateChanged(item.uid, item.processState);
+ boolean doReport = true;
+ if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+ final int lastState = reg.lastProcStates.get(item.uid,
+ ActivityManager.PROCESS_STATE_UNKNOWN);
+ if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
+ final boolean lastAboveCut = lastState <= reg.cutpoint;
+ final boolean newAboveCut = item.processState <= reg.cutpoint;
+ doReport = lastAboveCut != newAboveCut;
+ } else {
+ doReport = item.processState
+ != ActivityManager.PROCESS_STATE_NONEXISTENT;
+ }
+ }
+ if (doReport) {
+ if (reg.lastProcStates != null) {
+ reg.lastProcStates.put(item.uid, item.processState);
+ }
+ observer.onUidStateChanged(item.uid, item.processState);
+ }
}
if (VALIDATE_UID_STATES && i == 0) {
validateUid.curProcState = validateUid.setProcState
@@ -6447,11 +6490,12 @@
// SDK can see it. Since access to the serial is now behind a
// permission we push down the value.
String buildSerial = Build.UNKNOWN;
- if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+ // TODO: SHTOPSHIP Uncomment the check when clients migrate
+// if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
.getSerial();
- }
+// }
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
@@ -7429,6 +7473,15 @@
@Override
public void enterPictureInPictureMode(IBinder token) {
+ enterPictureInPictureMode(token, DEFAULT_DISPLAY, null /* aspectRatio */);
+ }
+
+ @Override
+ public void enterPictureInPictureModeWithAspectRatio(IBinder token, float aspectRatio) {
+ enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio);
+ }
+
+ public void enterPictureInPictureMode(IBinder token, int displayId, Float aspectRatio) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
@@ -7438,7 +7491,6 @@
}
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-
if (r == null) {
throw new IllegalStateException("enterPictureInPictureMode: "
+ "Can't find activity for token=" + token);
@@ -7449,21 +7501,55 @@
+ "Picture-In-Picture not supported for r=" + r);
}
- // Use the default launch bounds for pinned stack if it doesn't exist yet or use the
- // current bounds.
- final ActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID);
- final Rect bounds = (pinnedStack != null)
- ? pinnedStack.mBounds
- : mWindowManager.getPictureInPictureDefaultBounds(DEFAULT_DISPLAY);
+ if (aspectRatio != null && !isValidPictureInPictureAspectRatio(aspectRatio)) {
+ throw new IllegalArgumentException(String.format("enterPictureInPictureMode: "
+ + "Aspect ratio is too extreme (must be between %f and %f).",
+ mMinPipAspectRatio, mMaxPipAspectRatio));
+ }
- mStackSupervisor.moveActivityToPinnedStackLocked(
- r, "enterPictureInPictureMode", bounds);
+ final Rect bounds = isValidPictureInPictureAspectRatio(aspectRatio)
+ ? mWindowManager.getPictureInPictureBounds(displayId, aspectRatio)
+ : mWindowManager.getPictureInPictureDefaultBounds(displayId);
+ mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
+ bounds);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ @Override
+ public void setPictureInPictureAspectRatio(IBinder token, float aspectRatio) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r == null || r.getStack().mStackId != PINNED_STACK_ID) {
+ throw new IllegalStateException("setPictureInPictureAspectRatio: "
+ + "Requesting activity must be in picture-in-picture mode.");
+ }
+
+ if (!isValidPictureInPictureAspectRatio(aspectRatio)) {
+ throw new IllegalArgumentException(String.format(
+ "setPictureInPictureAspectRatio: Aspect ratio is too extreme (must be "
+ + "between %f and %f).", mMinPipAspectRatio,
+ mMaxPipAspectRatio));
+ }
+
+ mWindowManager.setPictureInPictureAspectRatio(aspectRatio);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ private boolean isValidPictureInPictureAspectRatio(Float aspectRatio) {
+ if (aspectRatio == null) {
+ return false;
+ }
+ return mMinPipAspectRatio <= aspectRatio && aspectRatio <= mMaxPipAspectRatio;
+ }
+
// =========================================================
// PROCESS INFO
// =========================================================
@@ -7751,38 +7837,43 @@
public int getAppStartMode(int uid, String packageName) {
synchronized (this) {
- return checkAllowBackgroundLocked(uid, packageName, -1, true);
+ return checkAllowBackgroundLocked(uid, packageName, -1, false);
}
}
int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
- boolean allowWhenForeground) {
+ boolean alwaysRestrict) {
UidRecord uidRec = mActiveUids.get(uid);
- if (!mLenientBackgroundCheck) {
- if (!allowWhenForeground || uidRec == null
- || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ if (uidRec == null || alwaysRestrict || uidRec.idle) {
+ boolean ephemeral;
+ if (uidRec == null) {
+ ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
+ UserHandle.getUserId(uid), packageName);
+ } else {
+ ephemeral = uidRec.ephemeral;
+ }
+
+ if (ephemeral) {
+ // We are hard-core about ephemeral apps not running in the background.
+ return ActivityManager.APP_START_MODE_DISABLED;
+ } else {
+ if (callingPid >= 0) {
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (proc != null && proc.curProcState
+ < ActivityManager.PROCESS_STATE_RECEIVER) {
+ // Whoever is instigating this is in the foreground, so we will allow it
+ // to go through.
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
+ }
if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
packageName) != AppOpsManager.MODE_ALLOWED) {
return ActivityManager.APP_START_MODE_DELAYED;
}
}
-
- } else if (uidRec == null || uidRec.idle) {
- if (callingPid >= 0) {
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(callingPid);
- }
- if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) {
- // Whoever is instigating this is in the foreground, so we will allow it
- // to go through.
- return ActivityManager.APP_START_MODE_NORMAL;
- }
- }
- if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName)
- != AppOpsManager.MODE_ALLOWED) {
- return ActivityManager.APP_START_MODE_DELAYED;
- }
}
return ActivityManager.APP_START_MODE_NORMAL;
}
@@ -11829,25 +11920,6 @@
}
@Override
- public void setLenientBackgroundCheck(boolean enabled) {
- enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
- "setLenientBackgroundCheck()");
-
- long ident = Binder.clearCallingIdentity();
- try {
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0);
-
- synchronized (this) {
- mLenientBackgroundCheck = enabled;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
public void setActivityController(IActivityController controller, boolean imAMonkey) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"setActivityController()");
@@ -12071,6 +12143,15 @@
!= null;
}
+ @Override
+ public boolean requestAutoFillData(IResultReceiver receiver, Bundle receiverExtras,
+ IBinder activityToken) {
+ return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null, receiver,
+ receiverExtras, activityToken, true, true,
+ UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+ != null;
+ }
+
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
@@ -12195,6 +12276,12 @@
sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
pae.receiverExtras);
+ IBinder autoFillCallback =
+ extras.getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK);
+ if (autoFillCallback != null) {
+ sendBundle.putBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK,
+ autoFillCallback);
+ }
}
}
if (sendReceiver != null) {
@@ -12245,13 +12332,15 @@
}
@Override
- public void registerUidObserver(IUidObserver observer, int which, String callingPackage) {
+ public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
+ String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
"registerUidObserver");
}
synchronized (this) {
- mUidObservers.register(observer, which);
+ mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(),
+ callingPackage, which, cutpoint));
}
}
@@ -12897,7 +12986,7 @@
}
}
} else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
- && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) {
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
@@ -12944,8 +13033,6 @@
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
- final boolean lenientBackgroundCheck =
- Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
@@ -12966,7 +13053,6 @@
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
- mLenientBackgroundCheck = lenientBackgroundCheck;
mSupportsLeanbackOnly = supportsLeanbackOnly;
mForceResizableActivities = forceResizable;
if (supportsMultiWindow || forceResizable) {
@@ -12993,6 +13079,10 @@
com.android.internal.R.dimen.thumbnail_width);
mThumbnailHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.thumbnail_height);
+ mMinPipAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+ mMaxPipAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
com.android.internal.R.string.config_appsNotReportingCrashes));
mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -14332,7 +14422,7 @@
pw.print(" ");
for (int i=0; i<ass.mStateTimes.length; i++) {
long amt = ass.mStateTimes[i];
- if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
amt += now - ass.mLastStateUptime;
}
if (amt != 0) {
@@ -14341,7 +14431,7 @@
i + ActivityManager.MIN_PROCESS_STATE));
pw.print("=");
TimeUtils.formatDuration(amt, pw);
- if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
pw.print("*");
}
}
@@ -14613,6 +14703,43 @@
pw.print(mode); pw.println();
}
}
+ final int NI = mUidObservers.getRegisteredCallbackCount();
+ boolean printed = false;
+ for (int i=0; i<NI; i++) {
+ final UidObserverRegistration reg = (UidObserverRegistration)
+ mUidObservers.getRegisteredCallbackCookie(i);
+ if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
+ if (!printed) {
+ pw.println(" mUidObservers:");
+ printed = true;
+ }
+ pw.print(" "); UserHandle.formatUid(pw, reg.uid);
+ pw.print(" "); pw.print(reg.pkg); pw.print(":");
+ if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
+ pw.print(" IDLE");
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+ pw.print(" ACT" );
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) {
+ pw.print(" GONE");
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+ pw.print(" STATE");
+ pw.print(" (cut="); pw.print(reg.cutpoint);
+ pw.print(")");
+ }
+ pw.println();
+ if (reg.lastProcStates != null) {
+ final int NJ = reg.lastProcStates.size();
+ for (int j=0; j<NJ; j++) {
+ pw.print(" Last ");
+ UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j));
+ pw.print(": "); pw.println(reg.lastProcStates.valueAt(j));
+ }
+ }
+ }
+ }
}
if (dumpPackage == null) {
pw.println(" mWakefulness="
@@ -14702,9 +14829,8 @@
}
}
if (dumpPackage == null) {
- if (mAlwaysFinishActivities || mLenientBackgroundCheck) {
- pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
- + " mLenientBackgroundCheck=" + mLenientBackgroundCheck);
+ if (mAlwaysFinishActivities) {
+ pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities);
}
if (mController != null) {
pw.println(" mController=" + mController
@@ -20629,6 +20755,7 @@
pendingChange.change = change;
pendingChange.processState = uidRec != null
? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+ pendingChange.ephemeral = uidRec.ephemeral;
// Directly update the power manager, since we sit on top of it and it is critical
// it be kept in sync (so wake locks will be held as soon as appropriate).
@@ -20996,8 +21123,11 @@
} else {
// Keeping this process, update its uid.
final UidRecord uidRec = app.uidRecord;
- if (uidRec != null && uidRec.curProcState > app.curProcState) {
- uidRec.curProcState = app.curProcState;
+ if (uidRec != null) {
+ uidRec.ephemeral = app.info.isEphemeralApp();
+ if (uidRec.curProcState > app.curProcState) {
+ uidRec.curProcState = app.curProcState;
+ }
}
}
@@ -21256,6 +21386,63 @@
}
}
+ @Override
+ public void makePackageIdle(String packageName, int userId) {
+ if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: makePackageIdle() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ final int callingPid = Binder.getCallingPid();
+ userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
+ userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null);
+ long callingId = Binder.clearCallingIdentity();
+ synchronized(this) {
+ try {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ int pkgUid = -1;
+ try {
+ pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES
+ | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ throw new IllegalArgumentException("Unknown package name " + packageName);
+ }
+
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.startUidChanges();
+ }
+ final int appId = UserHandle.getAppId(pkgUid);
+ final int N = mActiveUids.size();
+ for (int i=N-1; i>=0; i--) {
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ final long bgTime = uidRec.lastBackgroundTime;
+ if (bgTime > 0 && !uidRec.idle) {
+ if (UserHandle.getAppId(uidRec.uid) == appId) {
+ if (userId == UserHandle.USER_ALL ||
+ userId == UserHandle.getUserId(uidRec.uid)) {
+ uidRec.idle = true;
+ Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
+ + " from package " + packageName + " user " + userId);
+ doStopUidLocked(uidRec.uid, uidRec);
+ }
+ }
+ }
+ }
+ } finally {
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.finishUidChanges();
+ }
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+ }
+
final void idleUids() {
synchronized (this) {
final int N = mActiveUids.size();
@@ -22077,6 +22264,15 @@
// no need to synchronize(this) just to read & return the value
return mSystemReady;
}
+
+ @Override
+ public void notifyKeyguardTrustedChanged() {
+ synchronized (ActivityManagerService.this) {
+ if (mKeyguardController.isKeyguardShowing()) {
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ }
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index abeea74f..14b843a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -80,6 +80,7 @@
import static android.app.ActivityManager.RESIZE_MODE_USER;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.view.Display.INVALID_DISPLAY;
final class ActivityManagerShellCommand extends ShellCommand {
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
@@ -114,6 +115,7 @@
private String mProfileFile;
private int mSamplingInterval;
private boolean mAutoStop;
+ private int mDisplayId;
private int mStackId;
final boolean mDumping;
@@ -169,6 +171,8 @@
return runKill(pw);
case "kill-all":
return runKillAll(pw);
+ case "make-idle":
+ return runMakeIdle(pw);
case "monitor":
return runMonitor(pw);
case "hang":
@@ -205,8 +209,6 @@
return runTrackAssociations(pw);
case "untrack-associations":
return runUntrackAssociations(pw);
- case "lenient-background-check":
- return runLenientBackgroundCheck(pw);
case "get-uid-state":
return getUidState(pw);
case "get-config":
@@ -249,6 +251,7 @@
mSamplingInterval = 0;
mAutoStop = false;
mUserId = defUser;
+ mDisplayId = INVALID_DISPLAY;
mStackId = INVALID_STACK_ID;
return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -278,6 +281,8 @@
mUserId = UserHandle.parseUserArg(getNextArgRequired());
} else if (opt.equals("--receiver-permission")) {
mReceiverPermission = getNextArgRequired();
+ } else if (opt.equals("--display")) {
+ mDisplayId = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--stack")) {
mStackId = Integer.parseInt(getNextArgRequired());
} else {
@@ -354,6 +359,10 @@
int res;
final long startTime = SystemClock.uptimeMillis();
ActivityOptions options = null;
+ if (mDisplayId != INVALID_DISPLAY) {
+ options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(mDisplayId);
+ }
if (mStackId != INVALID_STACK_ID) {
options = ActivityOptions.makeBasic();
options.setLaunchStackId(mStackId);
@@ -853,6 +862,22 @@
return 0;
}
+ int runMakeIdle(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_ALL;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ mInterface.makePackageIdle(getNextArgRequired(), userId);
+ return 0;
+ }
+
static final class MyActivityController extends IActivityController.Stub {
final IActivityManager mInterface;
final PrintWriter mPw;
@@ -1432,22 +1457,6 @@
return 0;
}
- int runLenientBackgroundCheck(PrintWriter pw) throws RemoteException {
- String arg = getNextArg();
- if (arg != null) {
- boolean state = Boolean.valueOf(arg) || "1".equals(arg);
- mInterface.setLenientBackgroundCheck(state);
- }
- synchronized (mInternal) {
- if (mInternal.mLenientBackgroundCheck) {
- pw.println("Lenient background check enabled");
- } else {
- pw.println("Lenient background check disabled");
- }
- }
- return 0;
- }
-
int getUidState(PrintWriter pw) throws RemoteException {
mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
"getUidState()");
@@ -2478,8 +2487,6 @@
pw.println(" Enable association tracking.");
pw.println(" untrack-associations");
pw.println(" Disable and clear association tracking.");
- pw.println(" lenient-background-check [<true|false>]");
- pw.println(" Optionally controls lenient background check mode, returns current mode.");
pw.println(" get-uid-state <UID>");
pw.println(" Gets the process state of an app given its <UID>.");
pw.println(" attach-agent <PROCESS> <FILE>");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index be8f21d..facfeb6 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -16,7 +16,7 @@
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0d79980..1bdef43 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1806,8 +1806,9 @@
final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
final boolean showWhenLocked = r.hasShowWhenLockedWindows();
+ final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
if (shouldBeVisible) {
- if (r.hasDismissKeyguardWindows() && mTopDismissingKeyguardActivity == null) {
+ if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
mTopDismissingKeyguardActivity = r;
}
@@ -1819,8 +1820,10 @@
}
if (keyguardShowing) {
- // If keyguard is showing, nothing is visible.
- return false;
+ // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
+ // right away.
+ return shouldBeVisible && mStackSupervisor.mKeyguardController
+ .canShowActivityWhileKeyguardShowing(dismissKeyguard);
} else if (keyguardLocked) {
// Show when locked windows above keyguard.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8bb0e1a..539ac16 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -38,6 +38,8 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_PRIVATE;
+import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
@@ -90,6 +92,7 @@
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -1483,16 +1486,35 @@
Slog.w(TAG, message);
return false;
}
- if (options != null && options.getLaunchTaskId() != -1) {
- final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS,
- callingPid, callingUid);
- if (startInTaskPerm != PERMISSION_GRANTED) {
- final String msg = "Permission Denial: starting " + intent.toString()
- + " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ") with launchTaskId="
- + options.getLaunchTaskId();
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
+ if (options != null) {
+ if (options.getLaunchTaskId() != INVALID_STACK_ID) {
+ final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS,
+ callingPid, callingUid);
+ if (startInTaskPerm != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with launchTaskId="
+ + options.getLaunchTaskId();
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+ // Check if someone tries to launch an activity on a private display with a different
+ // owner.
+ final int launchDisplayId = options.getLaunchDisplayId();
+ if (launchDisplayId != INVALID_DISPLAY) {
+ final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId);
+ if (activityDisplay != null
+ && (activityDisplay.mDisplay.getFlags() & FLAG_PRIVATE) != 0) {
+ if (activityDisplay.mDisplay.getOwnerUid() != callingUid) {
+ final String msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with launchDisplayId="
+ + launchDisplayId;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
}
}
@@ -1937,7 +1959,7 @@
}
ActivityStack getStack(int stackId, boolean createStaticStackIfNeeded, boolean createOnTop) {
- ActivityContainer activityContainer = mActivityContainers.get(stackId);
+ final ActivityContainer activityContainer = mActivityContainers.get(stackId);
if (activityContainer != null) {
return activityContainer.mStack;
}
@@ -1948,6 +1970,40 @@
return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
}
+ /**
+ * Get a topmost stack on the display, that is a valid launch stack for specified activity.
+ * If there is no such stack, new dynamic stack can be created.
+ * @param displayId Target display.
+ * @param r Activity that should be launched there.
+ * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
+ */
+ ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r) {
+ final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+ if (activityDisplay == null) {
+ throw new IllegalArgumentException(
+ "Display with displayId=" + displayId + " not found.");
+ }
+
+ // Return the topmost valid stack on the display.
+ for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack stack = activityDisplay.mStacks.get(i);
+ if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, r)) {
+ return stack;
+ }
+ }
+
+ // If there is no valid stack on the external display - check if new dynamic stack will do.
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ final int newDynamicStackId = getNextStackId();
+ if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, r)) {
+ return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/);
+ }
+ }
+
+ Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId);
+ return null;
+ }
+
ArrayList<ActivityStack> getStacks() {
ArrayList<ActivityStack> allStacks = new ArrayList<>();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2120,6 +2176,14 @@
final int size = tasks.size();
if (onTop) {
for (int i = 0; i < size; i++) {
+ final TaskRecord task = tasks.get(i);
+ if (fromStackId == PINNED_STACK_ID) {
+ // Update the return-to to reflect where the pinned stack task was moved
+ // from so that we retain the stack that was previously visible if the
+ // pinned stack is recreated. See moveActivityToPinnedStackLocked().
+ task.setTaskToReturnTo(getFocusedStack().getStackId() == HOME_STACK_ID
+ ? HOME_ACTIVITY_TYPE : APPLICATION_ACTIVITY_TYPE);
+ }
moveTaskToStackLocked(tasks.get(i).taskId,
FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
"moveTasksToFullscreenStack", ANIMATE, DEFER_RESUME);
@@ -2318,11 +2382,15 @@
* Restores a recent task to a stack
* @param task The recent task to be restored.
* @param stackId The stack to restore the task to (default launch stack will be used
- * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}).
+ * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}
+ * or is not a static stack).
* @return true if the task has been restored successfully.
*/
private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
- if (stackId == INVALID_STACK_ID) {
+ if (!StackId.isStaticStack(stackId)) {
+ // If stack is not static (or stack id is invalid) - use the default one.
+ // This means that tasks that were on external displays will be restored on the
+ // primary display.
stackId = task.getLaunchStackId();
} else if (stackId == DOCKED_STACK_ID && !task.canGoInDockedStack()) {
// Preferred stack is the docked stack, but the task can't go in the docked stack.
@@ -3496,7 +3564,10 @@
if (activityDisplay != null) {
ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- stacks.get(stackNdx).mActivityContainer.removeLocked();
+ final ActivityStack stack = stacks.get(stackNdx);
+ // TODO: Implement proper stack removal and ability to choose the behavior -
+ // remove stack completely or move it to other display.
+ moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY);
}
mActivityDisplays.remove(displayId);
}
@@ -4147,7 +4218,10 @@
}
}
- /** Remove the stack completely. */
+ /**
+ * Remove the stack completely. Must be called only when there are no tasks left in it,
+ * as this method does not finish running activities.
+ */
void removeLocked() {
if (DEBUG_STACK) Slog.d(TAG_STACK, "removeLocked: " + this + " from display="
+ mActivityDisplay + " Callers=" + Debug.getCallers(2));
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2bdf854..ccd94cb 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -31,6 +31,7 @@
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.isStaticStack;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -50,6 +51,8 @@
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.view.Display.INVALID_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -252,11 +255,7 @@
if (err == ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
- + "} from uid " + callingUid
- + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ?
- Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
- (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
- container.mActivityDisplay.mDisplayId)));
+ + "} from uid " + callingUid);
}
ActivityRecord sourceRecord = null;
@@ -1156,6 +1155,14 @@
// since the app transition will not be triggered through the resume channel.
mWindowManager.executeAppTransition();
} else {
+ // If the target stack was not previously focusable (previous top running activity
+ // on that stack was not visible) then any prior calls to move the stack to the
+ // will not update the focused stack. If starting the new activity now allows the
+ // task stack to be focusable, then ensure that we now update the focused stack
+ // accordingly.
+ if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
+ mTargetStack.moveToFront("startActivityUnchecked");
+ }
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
@@ -1896,12 +1903,14 @@
// The fullscreen stack can contain any task regardless of if the task is resizeable
// or not. So, we let the task go in the fullscreen task if it is the focus stack.
+ // Same also applies to dynamic stacks, as they behave similar to fullscreen stack.
// If the freeform or docked stack has focus, and the activity to be launched is resizeable,
// we can also put it in the focused stack.
final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
|| (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack())
- || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced());
+ || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced())
+ || !isStaticStack(focusedStackId);
if (canUseFocusedStack && (!newTask
|| mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
@@ -1909,7 +1918,7 @@
return mSupervisor.mFocusedStack;
}
- // We first try to put the task in the first dynamic stack.
+ // We first try to put the task in the first dynamic stack on home display.
final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
@@ -1938,16 +1947,29 @@
return mReuseTask.getStack();
}
+ final int launchDisplayId =
+ (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY;
+
final int launchStackId =
(aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
+ if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) {
+ throw new IllegalArgumentException(
+ "Stack and display id can't be set at the same time.");
+ }
+
if (isValidLaunchStackId(launchStackId, r)) {
return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
- } else if (launchStackId == DOCKED_STACK_ID) {
+ }
+ if (launchStackId == DOCKED_STACK_ID) {
// The preferred launch stack is the docked stack, but it isn't a valid launch stack
// for this activity, so we put the activity in the fullscreen stack.
return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
+ if (launchDisplayId != INVALID_DISPLAY) {
+ // Stack id has higher priority than display id.
+ return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r);
+ }
if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
return null;
@@ -1991,9 +2013,8 @@
}
}
- private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
- if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
- || !StackId.isStaticStack(stackId)) {
+ boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+ if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID) {
return false;
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index c19a571..7a122e6 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -18,7 +18,7 @@
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.ProcessCpuTracker;
import com.android.server.Watchdog;
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index c6befd7..9e29725 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -17,7 +17,7 @@
package com.android.server.am;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto;
import android.content.ActivityNotFoundException;
import android.content.Context;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 4e69162..8104a43 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -36,7 +36,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -595,8 +594,12 @@
}
if (!skip) {
final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
- filter.packageName, -1, true);
- if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
+ filter.packageName, -1, false);
+ if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) {
+ // XXX should we really not allow this? It means that while we are
+ // keeping an ephemeral app cached, its registered receivers will stop
+ // receiving broadcasts after it goes idle... so if it comes back to
+ // the foreground, it won't know what the current state of those broadcasts is.
Slog.w(TAG, "Background execution not allowed: receiving "
+ r.intent
+ " to " + filter.receiverList.app
@@ -1155,7 +1158,7 @@
if (!skip) {
final int allowed = mService.checkAllowBackgroundLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1,
- false);
+ true);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 722974b..f618fc7 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -112,3 +112,5 @@
# Report changing memory conditions (Values are ProcessStats.ADJ_MEM_FACTOR* constants)
30050 am_mem_factor (Current|1|5),(Previous|1|5)
+# UserState has changed
+30051 am_user_state_changed (id|1|5),(state|1|5)
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 98acc9c..9d8c383 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -154,6 +154,14 @@
}
}
+ /**
+ * @return True if we may show an activity while Keyguard is showing because we are in the
+ * process of dismissing it anyways, false otherwise.
+ */
+ boolean canShowActivityWhileKeyguardShowing(boolean dismissKeyguard) {
+ return dismissKeyguard && canDismissKeyguard();
+ }
+
private void visibilitiesUpdated() {
final boolean lastOccluded = mOccluded;
final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
@@ -215,7 +223,6 @@
&& mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
- mKeyguardGoingAway = true;
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2b00f86..1322ecf 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -371,9 +371,6 @@
public static String makeProcStateString(int curProcState) {
String procState;
switch (curProcState) {
- case -1:
- procState = "N ";
- break;
case ActivityManager.PROCESS_STATE_PERSISTENT:
procState = "P ";
break;
@@ -425,6 +422,9 @@
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
procState = "CE";
break;
+ case ActivityManager.PROCESS_STATE_NONEXISTENT:
+ procState = "N ";
+ break;
default:
procState = "??";
break;
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index d24c3a5..d1a15bd 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -29,6 +29,7 @@
int curProcState;
int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
long lastBackgroundTime;
+ boolean ephemeral;
boolean idle;
int numProcs;
@@ -43,6 +44,7 @@
int uid;
int change;
int processState;
+ boolean ephemeral;
}
ChangeItem pendingChange;
@@ -64,6 +66,9 @@
UserHandle.formatUid(sb, uid);
sb.append(' ');
sb.append(ProcessList.makeProcStateString(curProcState));
+ if (ephemeral) {
+ sb.append(" ephemeral");
+ }
if (lastBackgroundTime > 0) {
sb.append(" bg:");
TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 9697855..a0a04bb 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -75,7 +75,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.IntArray;
@@ -735,8 +735,8 @@
}
}
- private IMountService getMountService() {
- return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ private IStorageManager getStorageManager() {
+ return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
/**
@@ -980,10 +980,10 @@
// TODO Move this block outside of synchronized if it causes lock contention
if (!StorageManager.isUserKeyUnlocked(userId)) {
final UserInfo userInfo = getUserInfo(userId);
- final IMountService mountService = getMountService();
+ final IStorageManager storageManager = getStorageManager();
try {
// We always want to unlock user storage, even user is not started yet
- mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret);
+ storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
} catch (RemoteException | RuntimeException e) {
Slog.w(TAG, "Failed to unlock: " + e.getMessage());
}
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 48238b6..42c31b1 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -70,6 +70,7 @@
public boolean setState(int oldState, int newState) {
if (state == oldState) {
setState(newState);
+ EventLogTags.writeAmUserStateChanged(mHandle.getIdentifier(), newState);
return true;
} else {
Slog.w(TAG, "Expected user " + mHandle.getIdentifier() + " in state "
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index eb5e603..da016da 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -25,7 +25,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -1706,7 +1705,7 @@
private int getCurrentUserId() {
final long ident = Binder.clearCallingIdentity();
try {
- UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ UserInfo currentUser = ActivityManager.getService().getCurrentUser();
return currentUser.id;
} catch (RemoteException e) {
// Activity manager not running, nothing we can do assume user 0.
@@ -5124,7 +5123,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5463,7 +5462,7 @@
}
try {
final int uid = pkg.applicationInfo.uid;
- ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
+ ActivityManager.getService().killUid(UserHandle.getAppId(uid),
UserHandle.getUserId(uid),
"killBackgroundUserProcessesWithAudioRecordPermission");
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 5772a57..8d4f0a9 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -16,7 +16,7 @@
package com.android.server.clipboard;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -71,7 +71,7 @@
public ClipboardService(Context context) {
super(context);
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
mPm = getContext().getPackageManager();
mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index f1d01e0..372b2d8 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -29,14 +29,14 @@
import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
import android.os.Parcelable;
-import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.NetworkId;
/** {@hide} */
final public class IpConnectivityEventBuilder {
@@ -136,96 +136,107 @@
}
private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
- out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
- out.dhcpEvent.ifName = in.ifName;
- out.dhcpEvent.errorCode = in.errorCode;
+ IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+ dhcpEvent.ifName = in.ifName;
+ dhcpEvent.setErrorCode(in.errorCode);
+ out.setDhcpEvent(dhcpEvent);
}
private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
- out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
- out.dhcpEvent.ifName = in.ifName;
- out.dhcpEvent.stateTransition = in.msg;
- out.dhcpEvent.durationMs = in.durationMs;
+ IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+ dhcpEvent.ifName = in.ifName;
+ dhcpEvent.setStateTransition(in.msg);
+ dhcpEvent.durationMs = in.durationMs;
+ out.setDhcpEvent(dhcpEvent);
}
private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) {
- out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
- out.dnsLookupBatch.networkId = netIdOf(in.netId);
- out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
- out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
- out.dnsLookupBatch.latenciesMs = in.latenciesMs;
+ IpConnectivityLogClass.DNSLookupBatch dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
+ dnsLookupBatch.networkId = netIdOf(in.netId);
+ dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
+ dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
+ dnsLookupBatch.latenciesMs = in.latenciesMs;
+ out.setDnsLookupBatch(dnsLookupBatch);
}
private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
- out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
- out.ipProvisioningEvent.ifName = in.ifName;
- out.ipProvisioningEvent.eventType = in.eventType;
- out.ipProvisioningEvent.latencyMs = (int) in.durationMs;
+ IpConnectivityLogClass.IpProvisioningEvent ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
+ ipProvisioningEvent.ifName = in.ifName;
+ ipProvisioningEvent.eventType = in.eventType;
+ ipProvisioningEvent.latencyMs = (int) in.durationMs;
+ out.setIpProvisioningEvent(ipProvisioningEvent);
}
private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
- out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
- out.ipReachabilityEvent.ifName = in.ifName;
- out.ipReachabilityEvent.eventType = in.eventType;
+ IpConnectivityLogClass.IpReachabilityEvent ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
+ ipReachabilityEvent.ifName = in.ifName;
+ ipReachabilityEvent.eventType = in.eventType;
+ out.setIpReachabilityEvent(ipReachabilityEvent);
}
private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
- out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
- out.defaultNetworkEvent.networkId = netIdOf(in.netId);
- out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
- out.defaultNetworkEvent.transportTypes = in.transportTypes;
- out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
+ IpConnectivityLogClass.DefaultNetworkEvent defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
+ defaultNetworkEvent.networkId = netIdOf(in.netId);
+ defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
+ defaultNetworkEvent.transportTypes = in.transportTypes;
+ defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
+ out.setDefaultNetworkEvent(defaultNetworkEvent);
}
private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
- out.networkEvent = new IpConnectivityLogClass.NetworkEvent();
- out.networkEvent.networkId = netIdOf(in.netId);
- out.networkEvent.eventType = in.eventType;
- out.networkEvent.latencyMs = (int) in.durationMs;
+ IpConnectivityLogClass.NetworkEvent networkEvent = new IpConnectivityLogClass.NetworkEvent();
+ networkEvent.networkId = netIdOf(in.netId);
+ networkEvent.eventType = in.eventType;
+ networkEvent.latencyMs = (int) in.durationMs;
+ out.setNetworkEvent(networkEvent);
}
private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
- out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
- out.validationProbeEvent.networkId = netIdOf(in.netId);
- out.validationProbeEvent.latencyMs = (int) in.durationMs;
- out.validationProbeEvent.probeType = in.probeType;
- out.validationProbeEvent.probeResult = in.returnCode;
+ IpConnectivityLogClass.ValidationProbeEvent validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
+ validationProbeEvent.networkId = netIdOf(in.netId);
+ validationProbeEvent.latencyMs = (int) in.durationMs;
+ validationProbeEvent.probeType = in.probeType;
+ validationProbeEvent.probeResult = in.returnCode;
+ out.setValidationProbeEvent(validationProbeEvent);
}
private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
- out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
- out.apfProgramEvent.lifetime = in.lifetime;
- out.apfProgramEvent.filteredRas = in.filteredRas;
- out.apfProgramEvent.currentRas = in.currentRas;
- out.apfProgramEvent.programLength = in.programLength;
+ IpConnectivityLogClass.ApfProgramEvent apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
+ apfProgramEvent.lifetime = in.lifetime;
+ apfProgramEvent.filteredRas = in.filteredRas;
+ apfProgramEvent.currentRas = in.currentRas;
+ apfProgramEvent.programLength = in.programLength;
if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
- out.apfProgramEvent.dropMulticast = true;
+ apfProgramEvent.dropMulticast = true;
}
if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
- out.apfProgramEvent.hasIpv4Addr = true;
+ apfProgramEvent.hasIpv4Addr = true;
}
+ out.setApfProgramEvent(apfProgramEvent);
}
private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
- out.apfStatistics = new IpConnectivityLogClass.ApfStatistics();
- out.apfStatistics.durationMs = in.durationMs;
- out.apfStatistics.receivedRas = in.receivedRas;
- out.apfStatistics.matchingRas = in.matchingRas;
- out.apfStatistics.droppedRas = in.droppedRas;
- out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
- out.apfStatistics.parseErrors = in.parseErrors;
- out.apfStatistics.programUpdates = in.programUpdates;
- out.apfStatistics.maxProgramSize = in.maxProgramSize;
+ IpConnectivityLogClass.ApfStatistics apfStatistics = new IpConnectivityLogClass.ApfStatistics();
+ apfStatistics.durationMs = in.durationMs;
+ apfStatistics.receivedRas = in.receivedRas;
+ apfStatistics.matchingRas = in.matchingRas;
+ apfStatistics.droppedRas = in.droppedRas;
+ apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
+ apfStatistics.parseErrors = in.parseErrors;
+ apfStatistics.programUpdates = in.programUpdates;
+ apfStatistics.maxProgramSize = in.maxProgramSize;
+ out.setApfStatistics(apfStatistics);
}
private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
- out.raEvent = new IpConnectivityLogClass.RaEvent();
- out.raEvent.routerLifetime = in.routerLifetime;
- out.raEvent.prefixValidLifetime = in.prefixValidLifetime;
- out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
- out.raEvent.routeInfoLifetime = in.routeInfoLifetime;
- out.raEvent.rdnssLifetime = in.rdnssLifetime;
- out.raEvent.dnsslLifetime = in.dnsslLifetime;
+ IpConnectivityLogClass.RaEvent raEvent = new IpConnectivityLogClass.RaEvent();
+ raEvent.routerLifetime = in.routerLifetime;
+ raEvent.prefixValidLifetime = in.prefixValidLifetime;
+ raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
+ raEvent.routeInfoLifetime = in.routeInfoLifetime;
+ raEvent.rdnssLifetime = in.rdnssLifetime;
+ raEvent.dnsslLifetime = in.dnsslLifetime;
+ out.setRaEvent(raEvent);
}
private static int[] bytesToInts(byte[] in) {
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 641c62f..42f439c 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -42,7 +42,7 @@
import java.util.ArrayList;
import java.util.function.ToIntFunction;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
/** {@hide} */
final public class IpConnectivityMetrics extends SystemService {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0beb227..6d96a10 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -71,6 +71,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.tethering.IControlsTethering;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
+import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.net.BaseNetworkObserver;
@@ -1939,7 +1940,8 @@
private void trackNewTetherableInterface(String iface, int interfaceType) {
TetherState tetherState;
tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
- interfaceType, mNMService, mStatsService, this));
+ interfaceType, mNMService, mStatsService, this,
+ new IPv6TetheringInterfaceServices(iface, mNMService)));
mTetherStates.put(iface, tetherState);
tetherState.mStateMachine.start();
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index c2c1a8c..dec2f77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -45,7 +45,7 @@
/**
* @hide
*/
-class IPv6TetheringInterfaceServices {
+public class IPv6TetheringInterfaceServices {
private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
private static final int RFC7421_IP_PREFIX_LENGTH = 64;
@@ -59,7 +59,7 @@
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
- IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+ public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
mIfName = ifname;
mNMService = nms;
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 6ca4e27..37221a9 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -94,14 +94,14 @@
public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController) {
+ IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
super(ifaceName, looper);
mNMService = nMService;
mStatsService = statsService;
mTetherController = tetherController;
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
- mIPv6TetherSvc = new IPv6TetheringInterfaceServices(mIfaceName, mNMService);
+ mIPv6TetherSvc = ipv6Svc;
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mInitialState = new InitialState();
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 0727629..3b4cef4 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,7 +20,6 @@
import android.accounts.Account;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
@@ -434,7 +433,7 @@
private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
try {
- return ActivityManagerNative.getDefault().checkUriPermission(
+ return ActivityManager.getService().checkUriPermission(
uri, pid, uid, modeFlags, userHandle, null);
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 03d95b2..11a3f11 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -21,7 +21,6 @@
import android.accounts.AccountManager;
import android.accounts.AccountManagerInternal;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
@@ -1020,7 +1019,7 @@
final int owningUid = syncAdapterInfo.uid;
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
try {
- if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
+ if (ActivityManager.getService().getAppStartMode(owningUid,
owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+ syncAdapterInfo.componentName
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 971989b..9c762cc 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -220,6 +220,11 @@
private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+ // The default color mode for default displays. Overrides the usual
+ // Display.Display.COLOR_MODE_DEFAULT for displays with the
+ // DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set.
+ private final int mDefaultDisplayDefaultColorMode;
+
// Temporary list of deferred work to perform when setting the display state.
// Only used by requestDisplayState. The field is self-synchronized and only
// intended for use inside of the requestGlobalDisplayStateInternal function.
@@ -232,6 +237,8 @@
mUiHandler = UiThread.getHandler();
mDisplayAdapterListener = new DisplayAdapterListener();
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+ mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
@@ -703,6 +710,14 @@
}
if (display != null && display.getPrimaryDisplayDeviceLocked() == device) {
int colorMode = mPersistentDataStore.getColorMode(device);
+ if (colorMode == Display.COLOR_MODE_INVALID) {
+ if ((device.getDisplayDeviceInfoLocked().flags
+ & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+ colorMode = mDefaultDisplayDefaultColorMode;
+ } else {
+ colorMode = Display.COLOR_MODE_DEFAULT;
+ }
+ }
display.setRequestedColorModeLocked(colorMode);
}
scheduleTraversalLocked(false);
@@ -1043,6 +1058,7 @@
pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
+ pw.println(" mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 5616fb9..47701b9 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -183,11 +183,11 @@
public int getColorMode(DisplayDevice device) {
if (!device.hasStableUniqueId()) {
- return Display.COLOR_MODE_DEFAULT;
+ return Display.COLOR_MODE_INVALID;
}
DisplayState state = getDisplayState(device.getUniqueId(), false);
if (state == null) {
- return Display.COLOR_MODE_DEFAULT;
+ return Display.COLOR_MODE_INVALID;
}
return state.getColorMode();
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 393199d..fbad8de 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -17,7 +17,7 @@
package com.android.server.dreams;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.content.ComponentName;
import android.content.Context;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 5297589..d65e257 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -17,7 +17,7 @@
package com.android.server.fingerprint;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
index 640a46f..c70ca7f 100644
--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
@@ -25,7 +25,7 @@
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.Arrays;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 49c4140..273bc64 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -465,7 +464,7 @@
private boolean isForegroundActivity(int uid, int pid) {
try {
List<RunningAppProcessInfo> procs =
- ActivityManagerNative.getDefault().getRunningAppProcesses();
+ ActivityManager.getService().getRunningAppProcesses();
int N = procs.size();
for (int i = 0; i < N; i++) {
RunningAppProcessInfo proc = procs.get(i);
@@ -1072,7 +1071,7 @@
private void listenForUserSwitches() {
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ ActivityManager.getService().registerUserSwitchObserver(
new SynchronousUserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId) throws RemoteException {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index a37dfed..c99d8be 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -30,7 +30,6 @@
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.job.JobInfo;
@@ -426,7 +425,7 @@
Slog.d(TAG, "Removing jobs for package " + pkgName
+ " in user " + userId);
}
- cancelJobsForUid(pkgUid, true);
+ cancelJobsForUid(pkgUid);
}
} catch (RemoteException|IllegalArgumentException e) {
/*
@@ -455,7 +454,7 @@
if (DEBUG) {
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
}
- cancelJobsForUid(uidRemoved, true);
+ cancelJobsForUid(uidRemoved);
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -509,15 +508,20 @@
updateUidState(uid, procState);
}
- @Override public void onUidGone(int uid) throws RemoteException {
+ @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ if (disabled) {
+ cancelJobsForUid(uid);
+ }
}
@Override public void onUidActive(int uid) throws RemoteException {
}
- @Override public void onUidIdle(int uid) throws RemoteException {
- cancelJobsForUid(uid, false);
+ @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+ if (disabled) {
+ cancelJobsForUid(uid);
+ }
}
};
@@ -562,7 +566,7 @@
String tag) {
JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
try {
- if (ActivityManagerNative.getDefault().getAppStartMode(uId,
+ if (ActivityManager.getService().getAppStartMode(uId,
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
+ " -- package not allowed to start");
@@ -646,26 +650,15 @@
* This will remove the job from the master list, and cancel the job if it was staged for
* execution or being executed.
* @param uid Uid to check against for removal of a job.
- * @param forceAll If true, all jobs for the uid will be canceled; if false, only those
- * whose apps are stopped.
+ *
*/
- public void cancelJobsForUid(int uid, boolean forceAll) {
+ public void cancelJobsForUid(int uid) {
List<JobStatus> jobsForUid;
synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(uid);
}
for (int i=0; i<jobsForUid.size(); i++) {
JobStatus toRemove = jobsForUid.get(i);
- if (!forceAll) {
- String packageName = toRemove.getServiceComponent().getPackageName();
- try {
- if (ActivityManagerNative.getDefault().getAppStartMode(uid, packageName)
- != ActivityManager.APP_START_MODE_DISABLED) {
- continue;
- }
- } catch (RemoteException e) {
- }
- }
cancelJobImpl(toRemove, null);
}
}
@@ -822,9 +815,10 @@
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
try {
- ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
+ ActivityManager.getService().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
- | ActivityManager.UID_OBSERVER_IDLE, null);
+ | ActivityManager.UID_OBSERVER_IDLE, ActivityManager.PROCESS_STATE_UNKNOWN,
+ null);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
@@ -1207,7 +1201,7 @@
public void process(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
try {
- if (ActivityManagerNative.getDefault().getAppStartMode(job.getUid(),
+ if (ActivityManager.getService().getAppStartMode(job.getUid(),
job.getJob().getService().getPackageName())
== ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Aborting job " + job.getUid() + ":"
@@ -1381,7 +1375,7 @@
int memLevel;
try {
- memLevel = ActivityManagerNative.getDefault().getMemoryTrimLevel();
+ memLevel = ActivityManager.getService().getMemoryTrimLevel();
} catch (RemoteException e) {
memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
}
@@ -1697,7 +1691,7 @@
long ident = Binder.clearCallingIdentity();
try {
- JobSchedulerService.this.cancelJobsForUid(uid, true);
+ JobSchedulerService.this.cancelJobsForUid(uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 5eb06ed..b44087c 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import android.content.Context;
@@ -30,6 +31,7 @@
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.TransferPipe;
import com.android.server.LocationManagerService;
import com.android.server.ServiceWatcher;
@@ -230,14 +232,9 @@
pw.flush();
try {
- service.asBinder().dump(fd, args);
- } catch (RemoteException e) {
- pw.println("service down (RemoteException)");
- Log.w(TAG, e);
- } catch (Exception e) {
- pw.println("service down (Exception)");
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ TransferPipe.dumpAsync(service.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ pw.println("Failed to dump location provider: " + e);
}
}
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
index 0eb8b55..8ed32f0 100644
--- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -17,7 +17,6 @@
package com.android.server.media;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
import android.media.IMediaResourceMonitor;
@@ -84,7 +83,7 @@
private String[] getPackageNamesFromPid(int pid) {
try {
for (ActivityManager.RunningAppProcessInfo proc :
- ActivityManagerNative.getDefault().getRunningAppProcesses()) {
+ ActivityManager.getService().getRunningAppProcesses()) {
if (proc.pid == pid) {
return proc.pkgList;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 3327b36..9740935 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -17,7 +17,6 @@
package com.android.server.media;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.PlaybackState;
import android.media.session.MediaSession;
@@ -74,7 +73,7 @@
private static boolean isFromMostRecentApp(MediaSessionRecord record) {
try {
List<ActivityManager.RecentTaskInfo> tasks =
- ActivityManagerNative.getDefault().getRecentTasks(1,
+ ActivityManager.getService().getRecentTasks(1,
ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
ActivityManager.RECENT_INCLUDE_PROFILES |
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index d8103fc..c1506b9 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -612,7 +612,7 @@
try {
mActivityManager.registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
- null);
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
// ignored; both services live in system_server
@@ -689,7 +689,7 @@
}
}
- @Override public void onUidGone(int uid) throws RemoteException {
+ @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
synchronized (mUidRulesFirstLock) {
removeUidStateUL(uid);
}
@@ -698,7 +698,7 @@
@Override public void onUidActive(int uid) throws RemoteException {
}
- @Override public void onUidIdle(int uid) throws RemoteException {
+ @Override public void onUidIdle(int uid, boolean disabled) throws RemoteException {
}
};
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f3ae2bc..a530b3d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,25 +16,24 @@
package com.android.server.notification;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_CHANNEL_BANNED;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
-import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
-import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
-import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
-import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationRankerService.REASON_SNOOZED;
-import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
-import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
+import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
+import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
+import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
+import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
@@ -51,7 +50,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
@@ -110,7 +108,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationRankerService;
+import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
@@ -125,7 +123,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
-import android.view.WindowManager;
import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -169,12 +166,10 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.TimeUnit;
/** {@hide} */
@@ -229,7 +224,6 @@
/** notification_enqueue status value for an ignored notification. */
private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
- private String mRankerServicePackageName;
private IActivityManager mAm;
AudioManager mAudioManager;
@@ -301,7 +295,7 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
- private NotificationRankers mRankerServices;
+ private NotificationAssistants mNotificationAssistants;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
@@ -605,7 +599,7 @@
REASON_DELEGATE_ERROR, null);
long ident = Binder.clearCallingIdentity();
try {
- ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
+ ActivityManager.getService().crashApplication(uid, initialPid, pkg,
"Bad notification posted from package " + pkg
+ ": " + message);
} catch (RemoteException e) {
@@ -758,7 +752,7 @@
}
}
mListeners.onPackagesChanged(removingPackage, pkgList);
- mRankerServices.onPackagesChanged(removingPackage, pkgList);
+ mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
mConditionProviders.onPackagesChanged(removingPackage, pkgList);
mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList);
}
@@ -808,7 +802,7 @@
// Refresh managed services
mConditionProviders.onUserSwitched(user);
mListeners.onUserSwitched(user);
- mRankerServices.onUserSwitched(user);
+ mNotificationAssistants.onUserSwitched(user);
mZenModeHelper.onUserSwitched(user);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
mUserProfiles.updateCache(context);
@@ -819,7 +813,7 @@
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
mConditionProviders.onUserUnlocked(user);
mListeners.onUserUnlocked(user);
- mRankerServices.onUserUnlocked(user);
+ mNotificationAssistants.onUserUnlocked(user);
mZenModeHelper.onUserUnlocked(user);
}
}
@@ -957,15 +951,11 @@
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- // This is the package that contains the AOSP framework update.
- mRankerServicePackageName = getContext().getPackageManager()
- .getServicesSystemSharedLibraryPackageName();
-
mHandler = new WorkerHandler();
mRankingThread.start();
String[] extractorNames;
@@ -1059,10 +1049,8 @@
// This is a MangedServices object that keeps track of the listeners.
mListeners = new NotificationListeners();
- // This is a MangedServices object that keeps track of the ranker.
- mRankerServices = new NotificationRankers();
- // Find the updatable ranker and register it.
- mRankerServices.registerRanker();
+ // This is a MangedServices object that keeps track of the assistant.
+ mNotificationAssistants = new NotificationAssistants();
mStatusBar = getLocalService(StatusBarManagerInternal.class);
if (mStatusBar != null) {
@@ -1209,7 +1197,7 @@
// bind to listener services.
mSettingsObserver.observe();
mListeners.onBootPhaseAppsCanStart();
- mRankerServices.onBootPhaseAppsCanStart();
+ mNotificationAssistants.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1682,10 +1670,10 @@
final StatusBarNotification sbnOut = new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
+ sbn.getNotificationChannel(),
sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
- 0, // hide score from apps
sbn.getNotification().clone(),
- sbn.getUser(), sbn.getPostTime());
+ sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
list.add(sbnOut);
}
}
@@ -1791,8 +1779,8 @@
long identity = Binder.clearCallingIdentity();
try {
ManagedServices manager =
- mRankerServices.isComponentEnabledForCurrentProfiles(component)
- ? mRankerServices
+ mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
+ ? mNotificationAssistants
: mListeners;
manager.setComponentState(component, true);
} finally {
@@ -2358,12 +2346,12 @@
}
@Override
- public void applyAdjustmentFromRankerService(INotificationListener token,
+ public void applyAdjustmentFromAssistantService(INotificationListener token,
Adjustment adjustment) throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- mRankerServices.checkServiceTokenLocked(token);
+ mNotificationAssistants.checkServiceTokenLocked(token);
applyAdjustmentLocked(adjustment);
}
mRankingHandler.requestSort();
@@ -2373,13 +2361,13 @@
}
@Override
- public void applyAdjustmentsFromRankerService(INotificationListener token,
+ public void applyAdjustmentsFromAssistantService(INotificationListener token,
List<Adjustment> adjustments) throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- mRankerServices.checkServiceTokenLocked(token);
+ mNotificationAssistants.checkServiceTokenLocked(token);
for (Adjustment adjustment : adjustments) {
applyAdjustmentLocked(adjustment);
}
@@ -2478,15 +2466,14 @@
}
final StatusBarNotification summarySbn =
new StatusBarNotification(adjustedSbn.getPackageName(),
- adjustedSbn.getOpPkg(), Integer.MAX_VALUE,
+ adjustedSbn.getOpPkg(),
+ adjustedSbn.getNotificationChannel(),
+ Integer.MAX_VALUE,
GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
adjustedSbn.getInitialPid(), summaryNotification,
adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
System.currentTimeMillis());
- summaryRecord = new NotificationRecord(getContext(), summarySbn,
- mRankingHelper.getNotificationChannel(adjustedSbn.getPackageName(),
- adjustedSbn.getUid(),
- adjustedSbn.getNotification().getNotificationChannel()));
+ summaryRecord = new NotificationRecord(getContext(), summarySbn);
summaries.put(pkg, summarySbn.getKey());
}
}
@@ -2632,9 +2619,8 @@
}
}
pw.println(')');
- pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
- pw.println("\n Notification ranker services:");
- mRankerServices.dump(pw, filter);
+ pw.println("\n Notification assistant services:");
+ mNotificationAssistants.dump(pw, filter);
}
if (!zenOnly) {
@@ -2734,9 +2720,11 @@
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
+ final NotificationChannel channel = mRankingHelper.getNotificationChannelWithFallback(pkg,
+ callingUid, notification.getChannel());
final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
- user);
+ pkg, opPkg, channel, id, tag, callingUid, callingPid, notification,
+ user, null, System.currentTimeMillis());
// Limit the number of notifications that any given package except the android
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
@@ -2799,9 +2787,7 @@
Notification.PRIORITY_MAX);
// setup local book-keeping
- final NotificationRecord r = new NotificationRecord(getContext(), n,
- mRankingHelper.getNotificationChannelWithFallback(pkg, callingUid,
- n.getNotification().getNotificationChannel()));
+ final NotificationRecord r = new NotificationRecord(getContext(), n);
mHandler.post(new EnqueueNotificationRunnable(userId, r));
idOut[0] = id;
@@ -2885,9 +2871,9 @@
}
}
- // tell the ranker service about the notification
- if (mRankerServices.isEnabled()) {
- mRankerServices.onNotificationEnqueued(r);
+ // tell the assistant service about the notification
+ if (mNotificationAssistants.isEnabled()) {
+ mNotificationAssistants.onNotificationEnqueued(r);
// TODO delay the code below here for 100ms or until there is an answer
}
@@ -2930,7 +2916,8 @@
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
if (old != null && !old.isCanceled) {
- mListeners.notifyRemovedLocked(n);
+ mListeners.notifyRemovedLocked(n,
+ NotificationListenerService.REASON_DELEGATE_ERROR);
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -3542,7 +3529,7 @@
// status bar
if (r.getNotification().getSmallIcon() != null) {
r.isCanceled = true;
- mListeners.notifyRemovedLocked(r.sbn);
+ mListeners.notifyRemovedLocked(r.sbn, reason);
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -4075,19 +4062,19 @@
}
}
- public class NotificationRankers extends ManagedServices {
+ public class NotificationAssistants extends ManagedServices {
- public NotificationRankers() {
+ public NotificationAssistants() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@Override
protected Config getConfig() {
Config c = new Config();
- c.caption = "notification ranker service";
- c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
- c.secureSettingName = null;
- c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
+ c.caption = "notification assistant service";
+ c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+ c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
c.clientLabel = R.string.notification_ranker_binding_label;
return c;
@@ -4117,10 +4104,10 @@
final StatusBarNotification sbn = r.sbn;
TrimCache trimCache = new TrimCache(sbn);
- // mServices is the list inside ManagedServices of all the rankers,
+ // mServices is the list inside ManagedServices of all the assistants,
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
- for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
+ for (final ManagedServiceInfo info : NotificationAssistants.this.mServices) {
boolean sbnVisible = isVisibleToListener(sbn, info);
if (!sbnVisible) {
continue;
@@ -4140,68 +4127,18 @@
private void notifyEnqueued(final ManagedServiceInfo info,
final StatusBarNotification sbn, int importance, boolean fromUser) {
- final INotificationListener ranker = (INotificationListener) info.service;
+ final INotificationListener assistant = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
- ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
+ assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
+ Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
}
}
public boolean isEnabled() {
return !mServices.isEmpty();
}
-
- @Override
- public void onUserSwitched(int user) {
- synchronized (mNotificationList) {
- int i = mServices.size()-1;
- while (i --> 0) {
- final ManagedServiceInfo info = mServices.get(i);
- unregisterService(info.service, info.userid);
- }
- }
- registerRanker();
- }
-
- @Override
- public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
- if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
- + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
- if (mRankerServicePackageName == null) {
- return;
- }
-
- if (pkgList != null && (pkgList.length > 0) && !removingPackage) {
- for (String pkgName : pkgList) {
- if (mRankerServicePackageName.equals(pkgName)) {
- registerRanker();
- }
- }
- }
- }
-
- protected void registerRanker() {
- // Find the updatable ranker and register it.
- if (mRankerServicePackageName == null) {
- Slog.w(TAG, "could not start ranker service: no package specified!");
- return;
- }
- Set<ComponentName> rankerComponents = queryPackageForServices(
- mRankerServicePackageName, UserHandle.USER_SYSTEM);
- Iterator<ComponentName> iterator = rankerComponents.iterator();
- if (iterator.hasNext()) {
- ComponentName rankerComponent = iterator.next();
- if (iterator.hasNext()) {
- Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
- } else {
- registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
- }
- } else {
- Slog.w(TAG, "could not start ranker service: none found");
- }
- }
}
public class NotificationListeners extends ManagedServices {
@@ -4295,7 +4232,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyRemoved(info, oldSbnLightClone, update);
+ notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
}
});
continue;
@@ -4314,7 +4251,7 @@
/**
* asynchronously notify all listeners about a removed notification
*/
- public void notifyRemovedLocked(StatusBarNotification sbn) {
+ public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
// make a copy in case changes are made to the underlying Notification object
// NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
// notification
@@ -4327,7 +4264,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyRemoved(info, sbnLight, update);
+ notifyRemoved(info, sbnLight, update, reason);
}
});
}
@@ -4391,14 +4328,14 @@
}
private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
- NotificationRankingUpdate rankingUpdate) {
+ NotificationRankingUpdate rankingUpdate, int reason) {
if (!info.enabledAndUserMatches(sbn.getUserId())) {
return;
}
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
- listener.onNotificationRemoved(sbnHolder, rankingUpdate);
+ listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index a1256db..5eacba6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -101,11 +101,8 @@
private String mUserExplanation;
private String mPeopleExplanation;
- private NotificationChannel mNotificationChannel;
-
@VisibleForTesting
- public NotificationRecord(Context context, StatusBarNotification sbn,
- NotificationChannel channel)
+ public NotificationRecord(Context context, StatusBarNotification sbn)
{
this.sbn = sbn;
mOriginalFlags = sbn.getNotification().flags;
@@ -114,7 +111,6 @@
mUpdateTimeMs = mCreationTimeMs;
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
- mNotificationChannel = channel;
mImportance = defaultImportance();
}
@@ -148,8 +144,8 @@
|| (n.defaults & Notification.DEFAULT_VIBRATE) != 0
|| n.sound != null
|| n.vibrate != null
- || mNotificationChannel.shouldVibrate()
- || mNotificationChannel.getRingtone() != null;
+ || sbn.getNotificationChannel().shouldVibrate()
+ || sbn.getNotificationChannel().getRingtone() != null;
stats.isNoisy = isNoisy;
if (!isNoisy && importance > IMPORTANCE_LOW) {
@@ -287,7 +283,7 @@
pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs);
pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects);
- pw.println(prefix + " mNotificationChannel= " + mNotificationChannel);
+ pw.println(prefix + " notificationChannel= " + notification.getChannel());
}
@@ -535,6 +531,6 @@
}
public NotificationChannel getChannel() {
- return mNotificationChannel;
+ return sbn.getNotificationChannel();
}
}
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index fb4050b..20d9813 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -34,7 +34,10 @@
import android.os.UserHandle;
import android.util.TimedRemoteCaller;
+import com.android.internal.os.TransferPipe;
+
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -110,13 +113,11 @@
.append((mRemoteInstance != null) ? "true" : "false").println();
pw.flush();
-
try {
- getRemoteInstanceLazy().asBinder().dump(fd, new String[] { prefix });
- } catch (TimeoutException te) {
- /* ignore */
- } catch (RemoteException re) {
- /* ignore */
+ TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+ new String[] { prefix });
+ } catch (IOException | TimeoutException | RemoteException e) {
+ pw.println("Failed to dump remote instance: " + e);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 00f0627..ee3f42b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -101,7 +101,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
@@ -192,8 +191,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
-import android.os.storage.IMountService;
-import android.os.storage.MountServiceInternal;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -208,6 +207,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
@@ -233,6 +233,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.IParcelFileDescriptorFactory;
import com.android.internal.os.InstallerConnection.InstallerException;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.telephony.CarrierAppUtils;
@@ -285,6 +286,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
@@ -336,7 +338,7 @@
*
* <pre>
* $ runtest -c android.content.pm.PackageManagerTests frameworks-core
- * $ cts-tradefed run commandAndExit cts -m AppSecurityTests
+ * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
* </pre>
*/
public class PackageManagerService extends IPackageManager.Stub {
@@ -1083,8 +1085,8 @@
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
- IMediaContainerService imcs =
- IMediaContainerService.Stub.asInterface(service);
+ final IMediaContainerService imcs = IMediaContainerService.Stub
+ .asInterface(Binder.allowBlocking(service));
mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
}
@@ -1470,10 +1472,11 @@
}
if (reportStatus) {
try {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
- PackageHelper.getMountService().finishMediaUpdate();
+ if (DEBUG_SD_INSTALL) Log.i(TAG,
+ "Invoking StorageManagerService call back");
+ PackageHelper.getStorageManager().finishMediaUpdate();
} catch (RemoteException e) {
- Log.e(TAG, "MountService not running?");
+ Log.e(TAG, "StorageManagerService not running?");
}
}
} break;
@@ -1885,6 +1888,11 @@
Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten");
deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS);
+
+ // Try very hard to release any references to this package
+ // so we don't risk the system server being killed due to
+ // open FDs
+ AttributeCache.instance().removePackage(ps.name);
}
mSettings.onVolumeForgotten(fsUuid);
@@ -4140,9 +4148,9 @@
final long token = Binder.clearCallingIdentity();
try {
if (sUserManager.isInitialized(userId)) {
- MountServiceInternal mountServiceInternal = LocalServices.getService(
- MountServiceInternal.class);
- mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName);
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -4543,7 +4551,7 @@
private void killUid(int appId, int userId, String reason) {
final long identity = Binder.clearCallingIdentity();
try {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (am != null) {
try {
am.killUid(appId, userId, reason);
@@ -7200,15 +7208,15 @@
// Before everything else, see whether we need to fstrim.
try {
- IMountService ms = PackageHelper.getMountService();
- if (ms != null) {
+ IStorageManager sm = PackageHelper.getStorageManager();
+ if (sm != null) {
boolean doTrim = false;
final long interval = android.provider.Settings.Global.getLong(
mContext.getContentResolver(),
android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
DEFAULT_MANDATORY_FSTRIM_INTERVAL);
if (interval > 0) {
- final long timeSinceLast = System.currentTimeMillis() - ms.lastMaintenance();
+ final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
if (timeSinceLast > interval) {
doTrim = true;
Slog.w(TAG, "No disk maintenance in " + timeSinceLast
@@ -7222,19 +7230,19 @@
}
if (!isFirstBoot() && dexOptDialogShown) {
try {
- ActivityManagerNative.getDefault().showBootMessage(
+ ActivityManager.getService().showBootMessage(
mContext.getResources().getString(
R.string.android_upgrading_fstrim), true);
} catch (RemoteException e) {
}
}
- ms.runMaintenance();
+ sm.runMaintenance();
}
} else {
- Slog.e(TAG, "Mount service unavailable!");
+ Slog.e(TAG, "storageManager service unavailable!");
}
} catch (RemoteException e) {
- // Can't happen; MountService is local
+ // Can't happen; StorageManagerService is local
}
}
@@ -7309,7 +7317,7 @@
if (showDialog) {
try {
- ActivityManagerNative.getDefault().showBootMessage(
+ ActivityManager.getService().showBootMessage(
mContext.getResources().getString(R.string.android_upgrading_apk,
numberOfPackagesVisited, numberOfPackagesToDexopt), true);
} catch (RemoteException e) {
@@ -9657,7 +9665,7 @@
// version of the application while the new one gets installed.
final long token = Binder.clearCallingIdentity();
try {
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (am != null) {
try {
am.killApplication(pkgName, appId, userId, reason);
@@ -10357,14 +10365,28 @@
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
BasePermission bp, PermissionsState origPermissions) {
- boolean allowed;
- allowed = (compareSignatures(
+ boolean privilegedPermission = (bp.protectionLevel
+ & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
+ boolean controlPrivappPermissions = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS;
+ boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
+ boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
+ if (controlPrivappPermissions && privilegedPermission && pkg.isPrivilegedApp()
+ && !platformPackage && platformPermission) {
+ ArraySet<String> wlPermissions = SystemConfig.getInstance()
+ .getPrivAppPermissions(pkg.packageName);
+ boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
+ if (!whitelisted) {
+ // Log for now. TODO Enforce permissions
+ Slog.w(TAG, "Privileged permission " + perm + " for package "
+ + pkg.packageName + " - not in privapp-permissions whitelist");
+ }
+ }
+ boolean allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
+ if (!allowed && privilegedPermission) {
if (isSystemApp(pkg)) {
// For updated system applications, a system permission
// is granted only if it had been defined by the original application.
@@ -11549,7 +11571,7 @@
@Override
public void run() {
try {
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
if (am == null) return;
final int[] resolvedUserIds;
if (userIds == null) {
@@ -11646,7 +11668,7 @@
}
Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
if (am != null) {
try {
am.startService(null, intent, null, mContext.getOpPackageName(),
@@ -11796,7 +11818,7 @@
if (!mUserManagerInternal.isUserRunning(userId)) {
return;
}
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
try {
// Deliver LOCKED_BOOT_COMPLETED first
Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
@@ -13758,7 +13780,7 @@
}
/**
- * Extract the MountService "container ID" from the full code path of an
+ * Extract the StorageManagerService "container ID" from the full code path of an
* .apk.
*/
static String cidFromCodePath(String fullCodePath) {
@@ -14223,11 +14245,13 @@
}
private File getNextCodePath(File targetDir, String packageName) {
- int suffix = 1;
File result;
+ SecureRandom random = new SecureRandom();
+ byte[] bytes = new byte[16];
do {
+ random.nextBytes(bytes);
+ String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
result = new File(targetDir, packageName + "-" + suffix);
- suffix++;
} while (result.exists());
return result;
}
@@ -16589,7 +16613,8 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (this) {
- mContainerService = IMediaContainerService.Stub.asInterface(service);
+ mContainerService = IMediaContainerService.Stub
+ .asInterface(Binder.allowBlocking(service));
notifyAll();
}
}
@@ -17086,7 +17111,7 @@
private void postPreferredActivityChangedBroadcast(int userId) {
mHandler.post(() -> {
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
if (am == null) {
return;
}
@@ -18062,8 +18087,10 @@
}
synchronized (mPackages) {
- if (uid == Process.SHELL_UID) {
+ if (uid == Process.SHELL_UID
+ && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Shell can only change whole packages between ENABLED and DISABLED_USER states
+ // unless it is a test package.
int oldState = pkgSetting.getEnabled(userId);
if (className == null
&&
@@ -18356,10 +18383,10 @@
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
- MountServiceInternal mountServiceInternal = LocalServices.getService(
- MountServiceInternal.class);
- mountServiceInternal.addExternalStoragePolicy(
- new MountServiceInternal.ExternalStorageMountPolicy() {
+ StorageManagerInternal StorageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ StorageManagerInternal.addExternalStoragePolicy(
+ new StorageManagerInternal.ExternalStorageMountPolicy() {
@Override
public int getMountMode(int uid, String packageName) {
if (Process.isIsolated(uid)) {
@@ -19237,7 +19264,7 @@
}
/**
- * Called by MountService when the initial ASECs to scan are available.
+ * Called by StorageManagerService when the initial ASECs to scan are available.
* Should block until all the ASEC containers are finished being scanned.
*/
public void scanAvailableAsecs() {
@@ -20749,7 +20776,7 @@
}
// kill any non-foreground processes so we restart them and
// grant/revoke the GID.
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
if (am != null) {
final long token = Binder.clearCallingIdentity();
try {
@@ -21216,6 +21243,14 @@
}
@Override
+ public boolean isPackageEphemeral(int userId, String packageName) {
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ return p != null ? p.applicationInfo.isEphemeralApp() : false;
+ }
+ }
+
+ @Override
public boolean wasPackageEverLaunched(String packageName, int userId) {
synchronized (mPackages) {
return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 42cc3a8..eef8ce2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1415,7 +1415,6 @@
VersionInfo ver = mVersion.get(volumeUuid);
if (ver == null) {
ver = new VersionInfo();
- ver.forceCurrent();
mVersion.put(volumeUuid, ver);
}
return ver;
@@ -2802,8 +2801,8 @@
"No settings file; creating initial state");
// It's enough to just touch version details to create them
// with default values
- findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL);
- findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL);
+ findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
+ findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
return false;
}
str = new FileInputStream(mSettingsFilename);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 38d69ed..d558b07 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -635,11 +635,7 @@
return false; // Shouldn't happen.
}
- // Always scan the settings app, since its version code is the same for DR and MR1.
- // TODO Fix it properly: b/32554059
- final boolean isSettings = "com.android.settings".equals(getPackageName());
-
- if (!isNewApp && !forceRescan && !isSettings) {
+ if (!isNewApp && !forceRescan) {
// Return if the package hasn't changed, ie:
// - version code hasn't change
// - lastUpdateTime hasn't change
@@ -656,11 +652,6 @@
return false;
}
}
- if (isSettings) {
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, "Always scan settings.");
- }
- }
} finally {
s.logDurationStat(Stats.PACKAGE_UPDATE_CHECK, start);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 37acf5c..7b877f7 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -21,7 +21,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.usage.UsageStatsManagerInternal;
@@ -467,8 +466,8 @@
}
@Override
- public void onUidGone(int uid) throws RemoteException {
- handleOnUidStateChanged(uid, ActivityManager.MAX_PROCESS_STATE);
+ public void onUidGone(int uid, boolean disabled) throws RemoteException {
+ handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
@Override
@@ -476,7 +475,7 @@
}
@Override
- public void onUidIdle(int uid) throws RemoteException {
+ public void onUidIdle(int uid, boolean disabled) throws RemoteException {
}
};
@@ -497,8 +496,7 @@
}
private boolean isProcessStateForeground(int processState) {
- return (processState != ActivityManager.PROCESS_STATE_NONEXISTENT)
- && (processState <= PROCESS_STATE_FOREGROUND_THRESHOLD);
+ return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
}
boolean isUidForegroundLocked(int uid) {
@@ -2667,8 +2665,7 @@
}
}
- rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime(),
- /* forceRescan=*/ false);
+ rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime());
}
} finally {
logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
@@ -2676,8 +2673,7 @@
verifyStates();
}
- private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime,
- boolean forceRescan) {
+ private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
final ShortcutUser user = getUserShortcutsLocked(userId);
// Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
@@ -2689,7 +2685,8 @@
// Then for each installed app, publish manifest shortcuts when needed.
forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
- user.rescanPackageIfNeeded(ai.packageName, forceRescan);
+
+ user.rescanPackageIfNeeded(ai.packageName, /* forceRescan= */ true);
});
// Write the time just before the scan, because there may be apps that have just
@@ -2937,32 +2934,26 @@
private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
Consumer<ApplicationInfo> callback) {
if (DEBUG) {
- Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
+ Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime
+ + " afterOta=" + afterOta);
}
final List<PackageInfo> list = getInstalledPackages(userId);
for (int i = list.size() - 1; i >= 0; i--) {
final PackageInfo pi = list.get(i);
// If the package has been updated since the last scan time, then scan it.
- // Also if it's a system app with no update, lastUpdateTime is not reliable, so
- // just scan it.
- if (pi.lastUpdateTime >= lastScanTime
- || (afterOta && isPureSystemApp(pi.applicationInfo))) {
+ // Also if it's right after an OTA, always re-scan all apps anyway, since the
+ // shortcut parser might have changed.
+ if (afterOta || (pi.lastUpdateTime >= lastScanTime)) {
if (DEBUG) {
- Slog.d(TAG, "Found updated package " + pi.packageName);
+ Slog.d(TAG, "Found updated package " + pi.packageName
+ + " updateTime=" + pi.lastUpdateTime);
}
callback.accept(pi.applicationInfo);
}
}
}
- /**
- * @return true if it's a system app with no updates.
- */
- private boolean isPureSystemApp(ApplicationInfo ai) {
- return ai.isSystemApp() && !ai.isUpdatedSystemApp();
- }
-
private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) {
final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId);
return (ai != null) && ((ai.flags & flags) == flags);
@@ -3213,8 +3204,8 @@
// Rescan all packages to re-publish manifest shortcuts and do other checks.
rescanUpdatedPackagesLocked(userId,
- 0, // lastScanTime = 0; rescan all packages.
- /* forceRescan= */ true);
+ 0 // lastScanTime = 0; rescan all packages.
+ );
saveUserLocked(userId);
}
@@ -3677,7 +3668,8 @@
@VisibleForTesting
void injectRegisterUidObserver(IUidObserver observer, int which) {
try {
- ActivityManagerNative.getDefault().registerUidObserver(observer, which, null);
+ ActivityManager.getService().registerUidObserver(observer, which,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
} catch (RemoteException shouldntHappen) {
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 67488ce..5b47b6f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -26,7 +26,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
@@ -757,11 +756,11 @@
long identity = Binder.clearCallingIdentity();
try {
if (enableQuietMode) {
- ActivityManagerNative.getDefault().stopUser(userHandle, /* force */true, null);
+ ActivityManager.getService().stopUser(userHandle, /* force */true, null);
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userHandle);
} else {
- ActivityManagerNative.getDefault().startUserInBackground(userHandle);
+ ActivityManager.getService().startUserInBackground(userHandle);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "fail to start/stop user for quiet mode", e);
@@ -1414,7 +1413,7 @@
// First, invalidate all cached values.
mCachedEffectiveUserRestrictions.clear();
- // We don't want to call into ActivityManagerNative while taking a lock, so we'll call
+ // We don't want to call into ActivityManagerService while taking a lock, so we'll call
// it on a handler.
final Runnable r = new Runnable() {
@Override
@@ -1422,9 +1421,9 @@
// Then get the list of running users.
final int[] runningUsers;
try {
- runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+ runningUsers = ActivityManager.getService().getRunningUserIds();
} catch (RemoteException e) {
- Log.w(LOG_TAG, "Unable to access ActivityManagerNative");
+ Log.w(LOG_TAG, "Unable to access ActivityManagerService");
return;
}
// Then re-calculate the effective restrictions and apply, only for running users.
@@ -2536,7 +2535,7 @@
if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
int res;
try {
- res = ActivityManagerNative.getDefault().stopUser(userHandle, /* force= */ true,
+ res = ActivityManager.getService().stopUser(userHandle, /* force= */ true,
new IStopUserCallback.Stub() {
@Override
public void userStopped(int userId) {
@@ -3259,7 +3258,7 @@
}
private int runList(PrintWriter pw) throws RemoteException {
- final IActivityManager am = ActivityManagerNative.getDefault();
+ final IActivityManager am = ActivityManager.getService();
final List<UserInfo> users = getUsers(false);
if (users == null) {
pw.println("Error: couldn't get users");
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 3df13a9..9fe0922 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
@@ -411,7 +410,7 @@
int currentUser = ActivityManager.getCurrentUser();
if (currentUser != userId && userId != UserHandle.USER_SYSTEM) {
try {
- ActivityManagerNative.getDefault().stopUser(userId, false, null);
+ ActivityManager.getService().stopUser(userId, false, null);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index a8bd4d2..d4adcc4 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -19,7 +19,7 @@
import com.android.internal.app.AlertController;
import com.android.internal.app.AlertController.AlertParams;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.EmergencyAffordanceManager;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
@@ -27,7 +27,6 @@
import com.android.internal.widget.LockPatternUtils;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -434,7 +433,7 @@
// Take an "interactive" bugreport.
MetricsLogger.action(mContext,
MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
- ActivityManagerNative.getDefault().requestBugReport(
+ ActivityManager.getService().requestBugReport(
ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
} catch (RemoteException e) {
}
@@ -452,7 +451,7 @@
try {
// Take a "full" bugreport.
MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
- ActivityManagerNative.getDefault().requestBugReport(
+ ActivityManager.getService().requestBugReport(
ActivityManager.BUGREPORT_OPTION_FULL);
} catch (RemoteException e) {
}
@@ -592,7 +591,7 @@
private UserInfo getCurrentUser() {
try {
- return ActivityManagerNative.getDefault().getCurrentUser();
+ return ActivityManager.getService().getCurrentUser();
} catch (RemoteException re) {
return null;
}
@@ -620,7 +619,7 @@
+ (isCurrentUser ? " \u2714" : "")) {
public void onPress() {
try {
- ActivityManagerNative.getDefault().switchUser(user.id);
+ ActivityManager.getService().switchUser(user.id);
} catch (RemoteException re) {
Log.e(TAG, "Couldn't switch user " + re);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b7067d2..ccdda13 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -114,7 +114,6 @@
import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
-import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
import android.app.ProgressDialog;
@@ -226,6 +225,7 @@
import com.android.server.LocalServices;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.AppTransition;
@@ -2677,9 +2677,10 @@
}
@Override
- public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
- int uiMode) {
- if (mHasNavigationBar) {
+ public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
+ // TODO(multi-display): Support navigation bar on secondary displays.
+ if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) {
// For a basic navigation bar, when we are in landscape mode we place
// the navigation bar to the side.
if (mNavigationBarCanMove && fullWidth > fullHeight) {
@@ -2698,9 +2699,10 @@
}
@Override
- public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
- int uiMode) {
- if (mHasNavigationBar) {
+ public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
+ // TODO(multi-display): Support navigation bar on secondary displays.
+ if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) {
// For a basic navigation bar, when we are in portrait mode we place
// the navigation bar to the bottom.
if (!mNavigationBarCanMove || fullWidth < fullHeight) {
@@ -2711,18 +2713,24 @@
}
@Override
- public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) {
- return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode);
+ public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
+ return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayId);
}
@Override
- public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) {
+ public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
// There is a separate status bar at the top of the display. We don't count that as part
// of the fixed decor, since it can hide; however, for purposes of configurations,
// we do want to exclude it since applications can't generally use that part
// of the screen.
- return getNonDecorDisplayHeight(
- fullWidth, fullHeight, rotation, uiMode) - mStatusBarHeight;
+ // TODO(multi-display): Support status bars on secondary displays.
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId)
+ - mStatusBarHeight;
+ }
+ return fullHeight;
}
@Override
@@ -3942,7 +3950,7 @@
public void onKeyguardExitResult(boolean success) {
if (success) {
try {
- ActivityManagerNative.getDefault().stopAppSwitches();
+ ActivityManager.getService().stopAppSwitches();
} catch (RemoteException e) {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
@@ -3956,7 +3964,7 @@
// no keyguard stuff to worry about, just launch home!
try {
- ActivityManagerNative.getDefault().stopAppSwitches();
+ ActivityManager.getService().stopAppSwitches();
} catch (RemoteException e) {
}
if (mRecentsVisible) {
@@ -6956,7 +6964,13 @@
/** {@inheritDoc} */
@Override
public void systemReady() {
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
+ mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
+ new StateCallback() {
+ @Override
+ public void onTrustedChanged() {
+ mWindowManagerFuncs.notifyKeyguardTrustedChanged();
+ }
+ });
mKeyguardDelegate.onSystemReady();
readCameraLensCoverState();
@@ -7333,7 +7347,7 @@
if (false) {
// This code always brings home to the front.
try {
- ActivityManagerNative.getDefault().stopAppSwitches();
+ ActivityManager.getService().stopAppSwitches();
} catch (RemoteException e) {
}
sendCloseSystemWindows();
@@ -7346,11 +7360,11 @@
/// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
Log.d(TAG, "UTS-TEST-MODE");
} else {
- ActivityManagerNative.getDefault().stopAppSwitches();
+ ActivityManager.getService().stopAppSwitches();
sendCloseSystemWindows();
Intent dock = createHomeDockIntent();
if (dock != null) {
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityAsUser(null, null, dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
@@ -7361,7 +7375,7 @@
}
}
}
- int result = ActivityManagerNative.getDefault()
+ int result = ActivityManager.getService()
.startActivityAsUser(null, null, mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 28f36f7..f37f987 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,8 +1,6 @@
package com.android.server.policy.keyguard;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -15,13 +13,11 @@
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
-import android.view.View;
import android.view.WindowManagerPolicy.OnKeyguardExitResult;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
-import com.android.server.LocalServices;
import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -47,6 +43,8 @@
private final Context mContext;
private final Handler mHandler;
private final KeyguardState mKeyguardState = new KeyguardState();
+ private final KeyguardStateMonitor.StateCallback mCallback;
+
private DrawnListener mDrawnListenerWhenConnect;
private static final class KeyguardState {
@@ -119,9 +117,10 @@
}
};
- public KeyguardServiceDelegate(Context context) {
+ public KeyguardServiceDelegate(Context context, KeyguardStateMonitor.StateCallback callback) {
mContext = context;
mHandler = UiThread.getHandler();
+ mCallback = callback;
}
public void bindService(Context context) {
@@ -155,7 +154,7 @@
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
mKeyguardService = new KeyguardServiceWrapper(mContext,
- IKeyguardService.Stub.asInterface(service));
+ IKeyguardService.Stub.asInterface(service), mCallback);
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
@@ -195,7 +194,7 @@
mKeyguardState.reset();
mHandler.post(() -> {
try {
- ActivityManagerNative.getDefault().setLockScreenShown(true);
+ ActivityManager.getService().setLockScreenShown(true);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index b457f8d..c4a0dd3 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -39,9 +39,10 @@
private IKeyguardService mService;
private String TAG = "KeyguardServiceWrapper";
- public KeyguardServiceWrapper(Context context, IKeyguardService service) {
+ public KeyguardServiceWrapper(Context context, IKeyguardService service,
+ KeyguardStateMonitor.StateCallback callback) {
mService = service;
- mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
+ mKeyguardStateMonitor = new KeyguardStateMonitor(context, service, callback);
}
@Override // Binder interface
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f19f0aa..941cd44 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -49,10 +49,12 @@
private int mCurrentUserId;
private final LockPatternUtils mLockPatternUtils;
+ private final StateCallback mCallback;
- public KeyguardStateMonitor(Context context, IKeyguardService service) {
+ public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
+ mCallback = callback;
try {
service.addStateMonitorCallback(this);
@@ -107,6 +109,7 @@
@Override // Binder interface
public void onTrustedChanged(boolean trusted) {
mTrusted = trusted;
+ mCallback.onTrustedChanged();
}
@Override // Binder interface
@@ -114,6 +117,10 @@
mHasLockscreenWallpaper = hasLockscreenWallpaper;
}
+ public interface StateCallback {
+ void onTrustedChanged();
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + TAG);
prefix += " ";
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 00700b8..b215998 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -25,7 +25,6 @@
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d755e58..1790554 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2731,6 +2731,8 @@
}
} else {
disabled = !wakeLock.mUidState.mActive &&
+ wakeLock.mUidState.mProcState
+ != ActivityManager.PROCESS_STATE_NONEXISTENT &&
wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER;
}
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index a920d54..cd966ef 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -43,8 +43,8 @@
import android.os.UserManager;
import android.os.Vibrator;
import android.os.SystemVibrator;
-import android.os.storage.IMountService;
-import android.os.storage.IMountShutdownObserver;
+import android.os.storage.IStorageShutdownObserver;
+import android.os.storage.IStorageManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -442,30 +442,30 @@
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
- // Shutdown MountService to ensure media is in a safe state
- IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
+ // Shutdown StorageManagerService to ensure media is in a safe state
+ IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
+ Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
actionDone();
}
};
- Log.i(TAG, "Shutting down MountService");
+ Log.i(TAG, "Shutting down StorageManagerService");
// Set initial variables and time out time.
mActionDone = false;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
- final IMountService mount = IMountService.Stub.asInterface(
+ final IStorageManager storageManager = IStorageManager.Stub.asInterface(
ServiceManager.checkService("mount"));
- if (mount != null) {
- mount.shutdown(observer);
+ if (storageManager != null) {
+ storageManager.shutdown(observer);
} else {
- Log.w(TAG, "MountService unavailable for shutdown");
+ Log.w(TAG, "StorageManagerService unavailable for shutdown");
}
} catch (Exception e) {
- Log.e(TAG, "Exception during MountService shutdown", e);
+ Log.e(TAG, "Exception during StorageManagerService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime - SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index f3b9b18..b5aa4a9 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.search;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.ISearchManager;
@@ -306,7 +305,7 @@
try {
Intent intent = new Intent(Intent.ACTION_ASSIST);
intent.setComponent(comp);
- IActivityManager am = ActivityManagerNative.getDefault();
+ IActivityManager am = ActivityManager.getService();
return am.launchAssistIntent(intent, ActivityManager.ASSIST_CONTEXT_BASIC, hint,
userHandle, args);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
new file mode 100644
index 0000000..23be9a3
--- /dev/null
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.storage;
+
+import android.annotation.CallSuper;
+import android.annotation.WorkerThread;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+import com.android.internal.os.AppFuseMount;
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+public class AppFuseBridge implements Runnable {
+ private static final String TAG = AppFuseBridge.class.getSimpleName();
+
+ private final FileDescriptor mDeviceFd;
+ private final FileDescriptor mProxyFd;
+ private final CountDownLatch mMountLatch = new CountDownLatch(1);
+
+ /**
+ * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge.
+ * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge.
+ */
+ private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) {
+ mDeviceFd = deviceFd;
+ mProxyFd = proxyFd;
+ }
+
+ public static AppFuseMount startMessageLoop(
+ int uid,
+ String name,
+ FileDescriptor deviceFd,
+ Handler handler,
+ ParcelFileDescriptor.OnCloseListener listener)
+ throws IOException, ErrnoException, InterruptedException {
+ final FileDescriptor localFd = new FileDescriptor();
+ final FileDescriptor remoteFd = new FileDescriptor();
+ // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries.
+ Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd);
+
+ // Caller must invoke #start() after instantiate AppFuseBridge.
+ // Otherwise FDs will be leaked.
+ final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd);
+ final Thread thread = new Thread(bridge, TAG);
+ thread.start();
+ try {
+ bridge.mMountLatch.await();
+ } catch (InterruptedException error) {
+ throw error;
+ }
+ return new AppFuseMount(
+ new File("/mnt/appfuse/" + uid + "_" + name),
+ ParcelFileDescriptor.fromFd(remoteFd, handler, listener));
+ }
+
+ @Override
+ public void run() {
+ // deviceFd and proxyFd must be closed in native_start_loop.
+ final int deviceFd = mDeviceFd.getInt$();
+ final int proxyFd = mProxyFd.getInt$();
+ mDeviceFd.setInt$(-1);
+ mProxyFd.setInt$(-1);
+ native_start_loop(deviceFd, proxyFd);
+ }
+
+ // Used by com_android_server_storage_AppFuse.cpp.
+ private void onMount() {
+ mMountLatch.countDown();
+ }
+
+ private native boolean native_start_loop(int deviceFd, int proxyFd);
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 62f5468..9d02940 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -26,7 +26,6 @@
import android.Manifest;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
import android.app.trust.ITrustManager;
@@ -868,7 +867,7 @@
}
if (locked) {
try {
- ActivityManagerNative.getDefault().notifyLockedProfile(userId);
+ ActivityManager.getService().notifyLockedProfile(userId);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 96662b5..3645c24 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -26,7 +26,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IWallpaperManager;
@@ -959,7 +958,7 @@
}, shutdownFilter);
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ ActivityManager.getService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 302f9f6..61319cf 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -16,7 +16,7 @@
package com.android.server.webkit;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -200,7 +200,7 @@
@Override
public void killPackageDependents(String packageName) {
try {
- ActivityManagerNative.getDefault().killPackageDependents(packageName,
+ ActivityManager.getService().killPackageDependents(packageName,
UserHandle.USER_ALL);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 6d97796..0a7454f 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -36,6 +36,7 @@
import com.android.server.SystemService;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Arrays;
/**
@@ -259,5 +260,18 @@
Binder.restoreCallingIdentity(callingId);
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump webviewupdate service from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ WebViewUpdateService.this.mImpl.dumpState(pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 453e745..1a77c68 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -30,6 +30,7 @@
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -673,6 +674,27 @@
mMinimumVersionCode = minimumVersionCode;
return mMinimumVersionCode;
}
+
+ public void dumpState(PrintWriter pw) {
+ synchronized (mLock) {
+ if (mCurrentWebViewPackage == null) {
+ pw.println(" Current WebView package is null");
+ } else {
+ pw.println(String.format(" Current WebView package (name, version): (%s, %s)",
+ mCurrentWebViewPackage.packageName,
+ mCurrentWebViewPackage.versionName));
+ }
+ pw.println(String.format(" Minimum WebView version code: %d",
+ mMinimumVersionCode));
+ pw.println(String.format(" Number of relros started: %d",
+ mNumRelroCreationsStarted));
+ pw.println(String.format(" Number of relros finished: %d",
+ mNumRelroCreationsFinished));
+ pw.println(String.format(" WebView package dirty: %b", mWebViewPackageDirty));
+ pw.println(String.format(" Any WebView package installed: %b",
+ mAnyWebViewInstalled));
+ }
+ }
}
private static boolean providerHasValidSignature(WebViewProviderInfo provider,
@@ -741,4 +763,14 @@
mSystemInterface.setMultiProcessEnabledFromContext(mContext);
}
}
+
+ /**
+ * Dump the state of this Service.
+ */
+ void dumpState(PrintWriter pw) {
+ pw.println("Current WebView Update Service state");
+ pw.println(String.format(" Fallback logic enabled: %b",
+ mSystemInterface.isFallbackLogicEnabled()));
+ mWebViewUpdater.dumpState(pw);
+ }
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 869e207..49ffa22 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -649,15 +649,12 @@
private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
- final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList();
- final int windowCount = windowList.size();
- for (int i = 0; i < windowCount; i++) {
- final WindowState windowState = windowList.get(i);
- if (windowState.isOnScreen() && windowState.isVisibleLw() &&
- !windowState.mWinAnimator.mEnterAnimationPending) {
- outWindows.put(windowState.mLayer, windowState);
+ dc.forAllWindows((w) -> {
+ if (w.isOnScreen() && w.isVisibleLw()
+ && !w.mWinAnimator.mEnterAnimationPending) {
+ outWindows.put(w.mLayer, w);
}
- }
+ }, false /* traverseTopToBottom */ );
}
private final class ViewportWindow {
@@ -1296,14 +1293,11 @@
private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
final DisplayContent dc = mWindowManagerService.getDefaultDisplayContentLocked();
- final ReadOnlyWindowList windowList = dc.getReadOnlyWindowList();
- final int windowCount = windowList.size();
- for (int i = 0; i < windowCount; i++) {
- final WindowState windowState = windowList.get(i);
- if (windowState.isVisibleLw()) {
- outWindows.put(windowState.mLayer, windowState);
+ dc.forAllWindows((w) -> {
+ if (w.isVisibleLw()) {
+ outWindows.put(w.mLayer, w);
}
- }
+ }, false /* traverseTopToBottom */ );
}
private class MyHandler extends Handler {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 622eece..0844d48 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -47,6 +47,7 @@
import static com.android.server.wm.WindowManagerService.logWithStack;
import android.os.Debug;
+import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
import com.android.server.wm.WindowManagerService.H;
@@ -66,6 +67,7 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.function.Function;
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -1269,6 +1271,23 @@
}
@Override
+ boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
+ // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
+ // before the non-exiting app tokens. So, we skip the exiting app tokens here.
+ // TODO: Investigate if we need to continue to do this or if we can just process them
+ // in-order.
+ if (mIsExiting && !waitingForReplacement()) {
+ return false;
+ }
+ return forAllWindowsUnchecked(callback, traverseTopToBottom);
+ }
+
+ boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ return super.forAllWindows(callback, traverseTopToBottom);
+ }
+
+ @Override
AppWindowToken asAppWindowToken() {
// I am an app window token!
return this;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 5bfece4..cf5cecda 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -96,8 +96,8 @@
private final class BoundsAnimator extends ValueAnimator
implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
private final AnimateBoundsUser mTarget;
- private final Rect mFrom;
- private final Rect mTo;
+ private final Rect mFrom = new Rect();
+ private final Rect mTo = new Rect();
private final Rect mTmpRect = new Rect();
private final Rect mTmpTaskBounds = new Rect();
private final boolean mMoveToFullScreen;
@@ -117,8 +117,8 @@
boolean moveToFullScreen, boolean replacement) {
super();
mTarget = target;
- mFrom = from;
- mTo = to;
+ mFrom.set(from);
+ mTo.set(to);
mMoveToFullScreen = moveToFullScreen;
mReplacement = replacement;
addUpdateListener(this);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ec4cdf2..e73acde 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -127,6 +127,7 @@
import android.view.WindowManagerPolicy;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.ToBooleanFunction;
import com.android.internal.view.IInputMethodClient;
import com.android.server.input.InputWindowHandle;
@@ -140,6 +141,8 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Utility class for keeping track of the WindowStates and other pertinent contents of a
@@ -724,7 +727,8 @@
win.getTouchableRegion(mTmpRegion);
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
- if (getDockedStackLocked() != null) {
+ // TODO(multi-display): Support docked stacks on secondary displays.
+ if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -1121,8 +1125,7 @@
for (int i = 0; i < windowCount; i++) {
final WindowState window = mWindows.get(i);
if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
- && !window.mPermanentlyHidden && !window.mAnimatingExit
- && !window.mRemoveOnExit) {
+ && !window.mPermanentlyHidden && !window.mWindowRemovalAllowed) {
return false;
}
}
@@ -1400,16 +1403,14 @@
/** Updates the layer assignment of windows on this display. */
void assignWindowLayers(boolean setLayoutNeeded) {
- mLayersController.assignWindowLayers(mWindows.getReadOnly());
+ mLayersController.assignWindowLayers(this);
if (setLayoutNeeded) {
setLayoutNeeded();
}
}
void adjustWallpaperWindows() {
- if (mWallpaperController.adjustWallpaperWindows(mWindows.getReadOnly())) {
- assignWindowLayers(true /*setLayoutNeeded*/);
- }
+ mWallpaperController.adjustWallpaperWindows(this);
}
/**
@@ -2457,14 +2458,6 @@
}
}
- ReadOnlyWindowList getReadOnlyWindowList() {
- return mWindows.getReadOnly();
- }
-
- void getWindows(WindowList output) {
- output.addAll(mWindows);
- }
-
// TODO: Super crazy long method that should be broken down...
boolean applySurfaceChangesTransaction(boolean recoveringMemory) {
@@ -3243,6 +3236,59 @@
}
@Override
+ boolean forAllWindows(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ if (traverseTopToBottom) {
+ if (super.forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ } else {
+ if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ if (super.forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
+ boolean traverseTopToBottom) {
+ // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the
+ // app tokens.
+ // TODO: Investigate if we need to continue to do this or if we can just process them
+ // in-order.
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+ for (int j = appTokens.size() - 1; j >= 0; --j) {
+ if (appTokens.get(j).forAllWindowsUnchecked(callback,
+ traverseTopToBottom)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; ++i) {
+ final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
+ final int appTokensCount = appTokens.size();
+ for (int j = 0; j < appTokensCount; j++) {
+ if (appTokens.get(j).forAllWindowsUnchecked(callback,
+ traverseTopToBottom)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
int getOrientation() {
if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
|| mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 6326148..f8b461e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -206,10 +206,12 @@
config.unset();
config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
config.screenWidthDp = (int)
- (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) /
+ (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode,
+ mDisplayContent.getDisplayId()) /
mDisplayContent.getDisplayMetrics().density);
config.screenHeightDp = (int)
- (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode) /
+ (mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, baseConfig.uiMode,
+ mDisplayContent.getDisplayId()) /
mDisplayContent.getDisplayMetrics().density);
final Context rotationContext = mService.mContext.createConfigurationContext(config);
mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
@@ -266,10 +268,8 @@
}
private void resetDragResizingChangeReported() {
- final ReadOnlyWindowList windowList = mDisplayContent.getReadOnlyWindowList();
- for (int i = windowList.size() - 1; i >= 0; i--) {
- windowList.get(i).resetDragResizingChangeReported();
- }
+ mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
+ true /* traverseTopToBottom */ );
}
void setWindow(WindowState window) {
diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
index 7cb6fc3..70478fe 100644
--- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.ClipData;
import android.net.Uri;
import android.os.Binder;
@@ -61,7 +61,7 @@
mActivityToken = activityToken;
// Will throw if Activity is not found.
- IBinder permissionOwner = ActivityManagerNative.getDefault().
+ IBinder permissionOwner = ActivityManager.getService().
getUriPermissionOwnerForActivity(mActivityToken);
doTake(permissionOwner);
@@ -71,7 +71,7 @@
long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
- ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+ ActivityManager.getService().grantUriPermissionFromOwner(
permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
mSourceUserId, mTargetUserId);
}
@@ -85,7 +85,7 @@
if (mActivityToken != null || mPermissionOwnerToken != null) {
return;
}
- mPermissionOwnerToken = ActivityManagerNative.getDefault().newUriPermissionOwner("drop");
+ mPermissionOwnerToken = ActivityManager.getService().newUriPermissionOwner("drop");
mTransientToken = transientToken;
mTransientToken.linkToDeath(this, 0);
@@ -101,7 +101,7 @@
IBinder permissionOwner = null;
if (mActivityToken != null) {
try {
- permissionOwner = ActivityManagerNative.getDefault().
+ permissionOwner = ActivityManager.getService().
getUriPermissionOwnerForActivity(mActivityToken);
} catch (Exception e) {
// Activity is destroyed, permissions already revoked.
@@ -117,7 +117,7 @@
}
for (int i = 0; i < mUris.size(); ++i) {
- ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
+ ActivityManager.getService().revokeUriPermissionFromOwner(
permissionOwner, mUris.get(i), mMode, mSourceUserId);
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d52168c..40b737d 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -271,11 +271,9 @@
Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
}
- final ReadOnlyWindowList windows = mDisplayContent.getReadOnlyWindowList();
- final int N = windows.size();
- for (int i = 0; i < N; i++) {
- sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
- }
+ mDisplayContent.forAllWindows(w -> {
+ sendDragStartedLw(w, touchX, touchY, mDataDescription);
+ }, false /* traverseTopToBottom */ );
}
/* helper - send a ACTION_DRAG_STARTED event, if the
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index a8eb75c..12c72e9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -26,7 +26,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Looper;
@@ -252,7 +252,7 @@
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
+ long timeout = ActivityManager.getService().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
diff --git a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
index 377071d..2eb186b 100644
--- a/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
+++ b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
@@ -19,7 +19,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.Handler;
@@ -101,7 +101,7 @@
if (dpm != null) {
try {
mAllowDisableKeyguard = dpm.getPasswordQuality(null,
- ActivityManagerNative.getDefault().getCurrentUser().id)
+ ActivityManager.getService().getCurrentUser().id)
== DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
} catch (RemoteException re) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 1ccf722..01a50b7 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -26,6 +26,7 @@
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
@@ -43,6 +44,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.policy.PipMotionHelper;
import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -55,7 +57,7 @@
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler = UiThread.getHandler();
private IPinnedStackListener mPinnedStackListener;
private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
@@ -67,6 +69,7 @@
// States that affect how the PIP can be manipulated
private boolean mInInteractiveMode;
+ private boolean mIsMinimized;
private boolean mIsImeShowing;
private int mImeHeight;
private ValueAnimator mBoundsAnimator = null;
@@ -101,6 +104,13 @@
}
@Override
+ public void setIsMinimized(final boolean isMinimized) {
+ mHandler.post(() -> {
+ mIsMinimized = isMinimized;
+ });
+ }
+
+ @Override
public void setSnapToEdge(final boolean snapToEdge) {
mHandler.post(() -> {
mSnapAlgorithm.setSnapToEdge(snapToEdge);
@@ -167,6 +177,25 @@
}
/**
+ * Returns the current bounds (or the default bounds if there are no current bounds) with the
+ * specified aspect ratio.
+ */
+ Rect getAspectRatioBounds(Rect stackBounds, float aspectRatio) {
+ // Save the snap fraction, calculate the aspect ratio based on the current bounds
+ final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
+ getMovementBounds(stackBounds));
+ final float radius = PointF.length(stackBounds.width(), stackBounds.height());
+ final int height = (int) Math.round(Math.sqrt((radius * radius) /
+ (aspectRatio * aspectRatio + 1)));
+ final int width = Math.round(height * aspectRatio);
+ final int left = (int) (stackBounds.centerX() - width / 2f);
+ final int top = (int) (stackBounds.centerY() - height / 2f);
+ stackBounds.set(left, top, left + width, top + height);
+ mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
+ return stackBounds;
+ }
+
+ /**
* @return the default bounds to show the PIP when there is no active PIP.
*/
Rect getDefaultBounds() {
@@ -227,6 +256,12 @@
false /* adjustForIme */);
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction);
+ if (mIsMinimized) {
+ final Point displaySize = new Point(mDisplayInfo.logicalWidth,
+ mDisplayInfo.logicalHeight);
+ mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds,
+ displaySize);
+ }
}
return postChangeStackBounds;
}
@@ -256,7 +291,12 @@
final Rect toBounds = new Rect(stackBounds);
if (adjustedForIme) {
// IME visible
- toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
+ if (stackBounds.top == prevMovementBounds.bottom) {
+ // If the PIP is resting on top of the IME, then adjust it with the hiding IME
+ toBounds.offsetTo(toBounds.left, movementBounds.bottom);
+ } else {
+ toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top));
+ }
} else {
// IME hidden
if (stackBounds.top == prevMovementBounds.bottom) {
@@ -314,5 +354,6 @@
pw.println();
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
pw.println(prefix + " mInInteractiveMode=" + mInInteractiveMode);
+ pw.println(prefix + " mIsMinimized=" + mIsMinimized);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f038135..88986e3 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -40,9 +40,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_NONE;
@@ -55,17 +53,13 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -78,7 +72,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
@@ -226,28 +219,6 @@
return false;
}
- void getWindows(WindowList output) {
- final int count = mChildren.size();
- for (int i = 0; i < count; ++i) {
- final DisplayContent dc = mChildren.get(i);
- dc.getWindows(output);
- }
- }
-
- void getWindows(WindowList output, boolean visibleOnly, boolean appsOnly) {
- final int numDisplays = mChildren.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
- for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState w = windowList.get(winNdx);
- if ((!visibleOnly || w.mWinAnimator.getShown())
- && (!appsOnly || w.mAppToken != null)) {
- output.add(w);
- }
- }
- }
- }
-
void getWindowsByName(WindowList output, String name) {
int objectId = 0;
// See if this is an object ID.
@@ -256,36 +227,20 @@
name = null;
} catch (RuntimeException e) {
}
- final int numDisplays = mChildren.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
- for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState w = windowList.get(winNdx);
- if (name != null) {
- if (w.mAttrs.getTitle().toString().contains(name)) {
- output.add(w);
- }
- } else if (System.identityHashCode(w) == objectId) {
- output.add(w);
- }
- }
- }
+
+ getWindowsByName(output, name, objectId);
}
- WindowState findWindow(int hashCode) {
- final int numDisplays = mChildren.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ReadOnlyWindowList windows = mChildren.get(displayNdx).getReadOnlyWindowList();
- final int numWindows = windows.size();
- for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
- final WindowState w = windows.get(winNdx);
- if (System.identityHashCode(w) == hashCode) {
- return w;
+ private void getWindowsByName(WindowList output, String name, int objectId) {
+ forAllWindows((w) -> {
+ if (name != null) {
+ if (w.mAttrs.getTitle().toString().contains(name)) {
+ output.add(w);
}
+ } else if (System.identityHashCode(w) == objectId) {
+ output.add(w);
}
- }
-
- return null;
+ }, true /* traverseTopToBottom */);
}
/**
@@ -406,81 +361,50 @@
}
void setSecureSurfaceState(int userId, boolean disabled) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState win = windows.get(winNdx);
- if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) {
- win.mWinAnimator.setSecureLocked(disabled);
- }
+ forAllWindows((w) -> {
+ if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) {
+ w.mWinAnimator.setSecureLocked(disabled);
}
- }
+ }, true /* traverseTopToBottom */);
}
void updateAppOpsState() {
- final int count = mChildren.size();
- for (int i = 0; i < count; ++i) {
- final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
- final int numWindows = windows.size();
- for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
- final WindowState win = windows.get(winNdx);
- if (win.mAppOp == OP_NONE) {
- continue;
- }
- final int mode = mService.mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
- win.getOwningPackage());
- win.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT);
+ forAllWindows((w) -> {
+ if (w.mAppOp == OP_NONE) {
+ return;
}
- }
+ final int mode = mService.mAppOps.checkOpNoThrow(w.mAppOp, w.getOwningUid(),
+ w.getOwningPackage());
+ w.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT);
+ }, false /* traverseTopToBottom */);
}
boolean canShowStrictModeViolation(int pid) {
- final int count = mChildren.size();
- for (int i = 0; i < count; ++i) {
- final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
- final int numWindows = windows.size();
- for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
- final WindowState ws = windows.get(winNdx);
- if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
- return true;
- }
- }
- }
- return false;
+ final WindowState win = getWindow((w) -> w.mSession.mPid == pid && w.isVisibleLw());
+ return win != null;
}
void closeSystemDialogs(String reason) {
- final int count = mChildren.size();
- for (int i = 0; i < count; ++i) {
- final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
- final int numWindows = windows.size();
- for (int j = 0; j < numWindows; ++j) {
- final WindowState w = windows.get(j);
- if (w.mHasSurface) {
- try {
- w.mClient.closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
+ forAllWindows((w) -> {
+ if (w.mHasSurface) {
+ try {
+ w.mClient.closeSystemDialogs(reason);
+ } catch (RemoteException e) {
}
}
- }
+ }, false /* traverseTopToBottom */);
}
void removeReplacedWindows() {
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows");
mService.openSurfaceTransaction();
try {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- DisplayContent dc = mChildren.get(i);
- final ReadOnlyWindowList windows = mChildren.get(i).getReadOnlyWindowList();
- for (int j = windows.size() - 1; j >= 0; j--) {
- final WindowState win = windows.get(j);
- final AppWindowToken aToken = win.mAppToken;
- if (aToken != null) {
- aToken.removeReplacedWindowIfNeeded(win);
- }
+ forAllWindows((w) -> {
+ final AppWindowToken aToken = w.mAppToken;
+ if (aToken != null) {
+ aToken.removeReplacedWindowIfNeeded(w);
}
- }
+ }, true /* traverseTopToBottom */);
} finally {
mService.closeSurfaceTransaction();
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
@@ -537,19 +461,15 @@
Slog.w(TAG_WM, "No leaked surfaces; killing applications!");
final SparseIntArray pidCandidates = new SparseIntArray();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ReadOnlyWindowList windows =
- mChildren.get(displayNdx).getReadOnlyWindowList();
- final int numWindows = windows.size();
- for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
- final WindowState ws = windows.get(winNdx);
- if (mService.mForceRemoves.contains(ws)) {
- continue;
+ mChildren.get(displayNdx).forAllWindows((w) -> {
+ if (mService.mForceRemoves.contains(w)) {
+ return;
}
- final WindowStateAnimator wsa = ws.mWinAnimator;
+ final WindowStateAnimator wsa = w.mWinAnimator;
if (wsa.mSurfaceController != null) {
pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
}
- }
+ }, false /* traverseTopToBottom */);
if (pidCandidates.size() > 0) {
int[] pids = new int[pidCandidates.size()];
@@ -760,9 +680,6 @@
WindowToken token = exitingTokens.get(i);
if (!token.hasVisible) {
exitingTokens.remove(i);
- if (token.windowType == TYPE_WALLPAPER) {
- displayContent.mWallpaperController.removeWallpaperToken(token);
- }
}
}
}
@@ -1088,17 +1005,14 @@
}
void dumpWindowsNoHeader(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) {
- final int numDisplays = mChildren.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ReadOnlyWindowList windowList = mChildren.get(displayNdx).getReadOnlyWindowList();
- for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState w = windowList.get(winNdx);
- if (windows == null || windows.contains(w)) {
- pw.println(" Window #" + winNdx + " " + w + ":");
- w.dump(pw, " ", dumpAll || windows != null);
- }
+ final int[] index = new int[1];
+ forAllWindows((w) -> {
+ if (windows == null || windows.contains(w)) {
+ pw.println(" Window #" + index[0] + " " + w + ":");
+ w.dump(pw, " ", dumpAll || windows != null);
+ index[0] = index[0] + 1;
}
- }
+ }, true /* traverseTopToBottom */);
}
void dumpTokens(PrintWriter pw, boolean dumpAll) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a0270c6..203ba72 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -132,6 +132,7 @@
// perfectly fit the region it would have been cropped to. We may also avoid certain logic we
// would otherwise apply while resizing, while resizing in the bounds animating mode.
private boolean mBoundsAnimating = false;
+ private Rect mBoundsAnimationTarget = new Rect();
// Temporary storage for the new bounds that should be used after the configuration change.
// Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
@@ -329,6 +330,30 @@
mDisplayContent.getLogicalDisplayRect(out);
}
+ /**
+ * Sets the bounds animation target bounds. This can't currently be done in onAnimationStart()
+ * since that is started on the UiThread.
+ */
+ void setAnimatingBounds(Rect bounds) {
+ if (bounds != null) {
+ mBoundsAnimationTarget.set(bounds);
+ } else {
+ mBoundsAnimationTarget.setEmpty();
+ }
+ }
+
+ /**
+ * @return the bounds that the task stack is currently being animated towards, or the current
+ * stack bounds if there is no animation in progress.
+ */
+ void getAnimatingBounds(Rect outBounds) {
+ if (!mBoundsAnimationTarget.isEmpty()) {
+ outBounds.set(mBoundsAnimationTarget);
+ return;
+ }
+ getBounds(outBounds);
+ }
+
/** Bounds of the stack with other system factors taken into consideration. */
@Override
public void getDimBounds(Rect out) {
@@ -1391,6 +1416,7 @@
public void onAnimationEnd() {
synchronized (mService.mWindowMap) {
mBoundsAnimating = false;
+ mBoundsAnimationTarget.setEmpty();
mService.requestTraversal();
}
if (mStackId == PINNED_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 250d381..8dbf2b3 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -17,9 +17,9 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -30,8 +30,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import android.os.Bundle;
import android.os.Debug;
@@ -55,17 +53,14 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
final private WindowManagerService mService;
- private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>();
+ private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>();
// If non-null, this is the currently visible window that is associated
// with the wallpaper.
private WindowState mWallpaperTarget = null;
// If non-null, we are in the middle of animating from one wallpaper target
- // to another, and this is the lower one in Z-order.
- private WindowState mLowerWallpaperTarget = null;
- // If non-null, we are in the middle of animating from one wallpaper target
- // to another, and this is the higher one in Z-order.
- private WindowState mUpperWallpaperTarget = null;
+ // to another, and this is the previous wallpaper target.
+ private WindowState mPrevWallpaperTarget = null;
private int mWallpaperAnimLayerAdjustment;
@@ -78,7 +73,7 @@
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
- WindowState mWaitingOnWallpaper;
+ private WindowState mWaitingOnWallpaper;
// The last time we had a timeout when waiting for a wallpaper.
private long mLastWallpaperTimeoutTime;
@@ -110,14 +105,6 @@
return mWallpaperTarget;
}
- WindowState getLowerWallpaperTarget() {
- return mLowerWallpaperTarget;
- }
-
- WindowState getUpperWallpaperTarget() {
- return mUpperWallpaperTarget;
- }
-
boolean isWallpaperTarget(WindowState win) {
return win == mWallpaperTarget;
}
@@ -135,7 +122,7 @@
*/
void startWallpaperAnimation(Animation a) {
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
token.startAnimation(a);
}
}
@@ -145,13 +132,11 @@
+ (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
+ " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
- + " upper=" + mUpperWallpaperTarget
- + " lower=" + mLowerWallpaperTarget);
+ + " prev=" + mPrevWallpaperTarget);
return (wallpaperTarget != null
&& (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
&& wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
- || mUpperWallpaperTarget != null
- || mLowerWallpaperTarget != null;
+ || mPrevWallpaperTarget != null;
}
boolean isWallpaperTargetAnimating() {
@@ -163,7 +148,7 @@
final boolean visible = isWallpaperVisible(mWallpaperTarget);
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
token.updateWallpaperVisibility(visible);
}
}
@@ -177,7 +162,7 @@
void hideWallpapers(final WindowState winGoingAway) {
if (mWallpaperTarget != null
- && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
+ && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
return;
}
if (mService.mAppTransition.isRunning()) {
@@ -189,11 +174,11 @@
final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
- final WindowToken token = mWallpaperTokens.get(i);
+ final WallpaperWindowToken token = mWallpaperTokens.get(i);
token.hideWallpaperToken(wasDeferred, "hideWallpapers");
if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
- + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
- + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
+ + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " "));
}
}
@@ -299,12 +284,10 @@
Bundle sendWindowWallpaperCommand(
WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
- if (window == mWallpaperTarget
- || window == mLowerWallpaperTarget
- || window == mUpperWallpaperTarget) {
+ if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
boolean doWait = sync;
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WindowToken token = mWallpaperTokens.get(curTokenNdx);
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
}
@@ -388,51 +371,52 @@
return mWallpaperAnimLayerAdjustment;
}
- private void findWallpaperTarget(ReadOnlyWindowList windows, FindWallpaperTargetResult result) {
+ private void findWallpaperTarget(DisplayContent dc , FindWallpaperTargetResult result) {
final WindowAnimator winAnimator = mService.mAnimator;
result.reset();
- WindowState w = null;
- int windowDetachedI = -1;
- boolean resetTopWallpaper = false;
- boolean inFreeformSpace = false;
- boolean replacing = false;
- boolean keyguardGoingAwayWithWallpaper = false;
- boolean needsShowWhenLockedWallpaper = false;
+ if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
+ // In freeform mode we set the wallpaper as its own target, so we don't need an
+ // additional window to make it visible.
+ result.setUseTopWallpaperAsTarget(true);
+ }
- for (int i = windows.size() - 1; i >= 0; i--) {
- w = windows.get(i);
+ dc.forAllWindows(w -> {
if ((w.mAttrs.type == TYPE_WALLPAPER)) {
- if (result.topWallpaper == null || resetTopWallpaper) {
- result.setTopWallpaper(w, i);
- resetTopWallpaper = false;
+ if (result.topWallpaper == null || result.resetTopWallpaper) {
+ result.setTopWallpaper(w);
+ result.resetTopWallpaper = false;
}
- continue;
+ return false;
}
- resetTopWallpaper = true;
+
+ result.resetTopWallpaper = true;
if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
// If this window's app token is hidden and not animating,
// it is of no interest to us.
if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Skipping hidden and not animating token: " + w);
- continue;
+ return false;
}
}
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
- + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
+ + " mDrawState=" + w.mWinAnimator.mDrawState);
- if (!inFreeformSpace) {
- TaskStack stack = w.getStack();
- inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ if (w.mWillReplaceWindow && mWallpaperTarget == null
+ && !result.useTopWallpaperAsTarget) {
+ // When we are replacing a window and there was wallpaper before replacement, we
+ // want to keep the window until the new windows fully appear and can determine the
+ // visibility, to avoid flickering.
+ result.setUseTopWallpaperAsTarget(true);
}
- replacing |= w.mWillReplaceWindow;
- keyguardGoingAwayWithWallpaper |= (w.mAppToken != null
+ final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null
&& AppTransition.isKeyguardGoingAwayTransit(
w.mAppToken.mAppAnimator.getTransit())
&& (w.mAppToken.mAppAnimator.getTransitFlags()
& TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
+ boolean needsShowWhenLockedWallpaper = false;
if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
&& mService.mPolicy.isKeyguardLocked()
&& mService.mPolicy.isKeyguardOccluded()) {
@@ -442,248 +426,147 @@
|| (w.mAppToken != null && !w.mAppToken.fillsParent());
}
+ if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
+ // Keep the wallpaper during Keyguard exit but also when it's needed for a
+ // non-fullscreen show when locked activity.
+ result.setUseTopWallpaperAsTarget(true);
+ }
+
final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
- result.setWallpaperTarget(w, i);
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
+ result.setWallpaperTarget(w);
if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
// The current wallpaper target is animating, so we'll look behind it for
// another possible target and figure out what is going on later.
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Win " + w + ": token animating, looking behind.");
- continue;
}
- break;
+ // Found a target! End search.
+ return true;
} else if (w == winAnimator.mWindowDetachedWallpaper) {
- windowDetachedI = i;
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found animating detached wallpaper target win: " + w);
+ result.setUseTopWallpaperAsTarget(true);
}
- }
+ return false;
+ }, true /* traverseTopToBottom */);
- if (result.wallpaperTarget != null) {
- return;
- }
-
- if (windowDetachedI >= 0) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
- result.setWallpaperTarget(w, windowDetachedI);
- } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) {
- // In freeform mode we set the wallpaper as its own target, so we don't need an
- // additional window to make it visible. When we are replacing a window and there was
- // wallpaper before replacement, we want to keep the window until the new windows fully
- // appear and can determine the visibility, to avoid flickering.
- result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
-
- } else if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
- // Keep the wallpaper during Keyguard exit but also when it's needed for a
- // non-fullscreen show when locked activity.
- result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
+ if (result.wallpaperTarget == null && result.useTopWallpaperAsTarget) {
+ result.setWallpaperTarget(result.topWallpaper);
}
}
private boolean isFullscreen(WindowManager.LayoutParams attrs) {
return attrs.x == 0 && attrs.y == 0
- && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
- && attrs.height == WindowManager.LayoutParams.MATCH_PARENT;
+ && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT;
}
/** Updates the target wallpaper if needed and returns true if an update happened. */
- private boolean updateWallpaperWindowsTarget(
- ReadOnlyWindowList windows, FindWallpaperTargetResult result) {
+ private void updateWallpaperWindowsTarget(DisplayContent dc,
+ FindWallpaperTargetResult result) {
WindowState wallpaperTarget = result.wallpaperTarget;
- int wallpaperTargetIndex = result.wallpaperTargetIndex;
if (mWallpaperTarget == wallpaperTarget
- || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) {
+ || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) {
- if (mLowerWallpaperTarget != null) {
- // Is it time to stop animating?
- if (!mLowerWallpaperTarget.isAnimatingLw()
- || !mUpperWallpaperTarget.isAnimatingLw()) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "No longer animating wallpaper targets!");
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
- mWallpaperTarget = wallpaperTarget;
- return true;
- }
+ if (mPrevWallpaperTarget == null) {
+ return;
}
- return false;
+ // Is it time to stop animating?
+ if (!mPrevWallpaperTarget.isAnimatingLw()) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
+ mPrevWallpaperTarget = null;
+ mWallpaperTarget = wallpaperTarget;
+ }
+ return;
}
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
+ "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget);
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
+ mPrevWallpaperTarget = null;
- WindowState oldW = mWallpaperTarget;
+ final WindowState prevWallpaperTarget = mWallpaperTarget;
mWallpaperTarget = wallpaperTarget;
- if (wallpaperTarget == null || oldW == null) {
- return true;
+ if (wallpaperTarget == null || prevWallpaperTarget == null) {
+ return;
}
// Now what is happening... if the current and new targets are animating,
// then we are in our super special mode!
- boolean oldAnim = oldW.isAnimatingLw();
+ boolean oldAnim = prevWallpaperTarget.isAnimatingLw();
boolean foundAnim = wallpaperTarget.isAnimatingLw();
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
"New animation: " + foundAnim + " old animation: " + oldAnim);
if (!foundAnim || !oldAnim) {
- return true;
+ return;
}
- int oldI = windows.indexOf(oldW);
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New i: " + wallpaperTargetIndex + " old i: " + oldI);
-
- if (oldI < 0) {
- return true;
+ if (dc.getWindow(w -> w == prevWallpaperTarget) == null) {
+ return;
}
final boolean newTargetHidden = wallpaperTarget.mAppToken != null
&& wallpaperTarget.mAppToken.hiddenRequested;
- final boolean oldTargetHidden = oldW.mAppToken != null
- && oldW.mAppToken.hiddenRequested;
+ final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null
+ && prevWallpaperTarget.mAppToken.hiddenRequested;
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "="
- + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "="
- + wallpaperTarget + " hidden=" + newTargetHidden);
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
+ + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
+ + " hidden=" + newTargetHidden);
- // Set the upper and lower wallpaper targets correctly,
- // and make sure that we are positioning the wallpaper below the lower.
- if (wallpaperTargetIndex > oldI) {
- // The new target is on top of the old one.
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target.");
- mUpperWallpaperTarget = wallpaperTarget;
- mLowerWallpaperTarget = oldW;
-
- wallpaperTarget = oldW;
- wallpaperTargetIndex = oldI;
- } else {
- // The new target is below the old one.
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target.");
- mUpperWallpaperTarget = oldW;
- mLowerWallpaperTarget = wallpaperTarget;
- }
+ mPrevWallpaperTarget = prevWallpaperTarget;
if (newTargetHidden && !oldTargetHidden) {
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
// Use the old target if new target is hidden but old target
// is not. If they're both hidden, still use the new target.
- mWallpaperTarget = oldW;
+ mWallpaperTarget = prevWallpaperTarget;
} else if (newTargetHidden == oldTargetHidden
&& !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
- && (mService.mOpeningApps.contains(oldW.mAppToken)
- || mService.mClosingApps.contains(oldW.mAppToken))) {
+ && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
+ || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
// If they're both hidden (or both not hidden), prefer the one that's currently in
// opening or closing app list, this allows transition selection logic to better
// determine the wallpaper status of opening/closing apps.
- mWallpaperTarget = oldW;
+ mWallpaperTarget = prevWallpaperTarget;
}
- result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
- return true;
+ result.setWallpaperTarget(wallpaperTarget);
}
- private boolean updateWallpaperWindowsTargetByLayer(ReadOnlyWindowList windows,
- FindWallpaperTargetResult result) {
-
- WindowState wallpaperTarget = result.wallpaperTarget;
- int wallpaperTargetIndex = result.wallpaperTargetIndex;
- boolean visible = wallpaperTarget != null;
-
- if (visible) {
- // The window is visible to the compositor...but is it visible to the user?
- // That is what the wallpaper cares about.
- visible = isWallpaperVisible(wallpaperTarget);
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
-
- // If the wallpaper target is animating, we may need to copy its layer adjustment.
- // Only do this if we are not transferring between two wallpaper targets.
- mWallpaperAnimLayerAdjustment =
- (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
- ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
-
- final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
- + TYPE_LAYER_OFFSET;
-
- // Now w is the window we are supposed to be behind... but we
- // need to be sure to also be behind any of its attached windows,
- // AND any starting window associated with it, AND below the
- // maximum layer the policy allows for wallpapers.
- while (wallpaperTargetIndex > 0) {
- final WindowState wb = windows.get(wallpaperTargetIndex - 1);
- final WindowState wbParentWindow = wb.getParentWindow();
- final WindowState wallpaperParentWindow = wallpaperTarget.getParentWindow();
- if (wb.mBaseLayer < maxLayer
- && wbParentWindow != wallpaperTarget
- && (wallpaperParentWindow == null || wbParentWindow != wallpaperParentWindow)
- && (wb.mAttrs.type != TYPE_APPLICATION_STARTING
- || wallpaperTarget.mToken == null
- || wb.mToken != wallpaperTarget.mToken)) {
- // This window is not related to the previous one in any
- // interesting way, so stop here.
- break;
- }
- wallpaperTarget = wb;
- wallpaperTargetIndex--;
- }
- } else {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
- }
-
- result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
- return visible;
- }
-
- private boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windows,
- WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
-
- // TODO(multidisplay): Wallpapers on main screen only.
- final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
-
- // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed.
- boolean changed = false;
+ private void updateWallpaperTokens(boolean visible) {
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WindowToken token = mWallpaperTokens.get(curTokenNdx);
- changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget,
- wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment);
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
+ token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment);
}
-
- return changed;
}
- boolean adjustWallpaperWindows(ReadOnlyWindowList windows) {
+ void adjustWallpaperWindows(DisplayContent dc) {
mService.mRoot.mWallpaperMayChange = false;
// First find top-most window that has asked to be on top of the wallpaper;
// all wallpapers go behind it.
- findWallpaperTarget(windows, mFindResults);
- final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
- final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
- WindowState wallpaperTarget = mFindResults.wallpaperTarget;
- int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
+ findWallpaperTarget(dc, mFindResults);
+ updateWallpaperWindowsTarget(dc, mFindResults);
- if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
- // There is no wallpaper target, so it goes at the bottom.
- // We will assume it is the same place as last time, if known.
- wallpaperTarget = mFindResults.topWallpaper;
- wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
- } else {
- // Okay i is the position immediately above the wallpaper.
- // Look at what is below it for later.
- wallpaperTarget = wallpaperTargetIndex > 0
- ? windows.get(wallpaperTargetIndex - 1) : null;
- }
+ // The window is visible to the compositor...but is it visible to the user?
+ // That is what the wallpaper cares about.
+ final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
if (visible) {
+ // If the wallpaper target is animating, we may need to copy its layer adjustment.
+ // Only do this if we are not transferring between two wallpaper targets.
+ mWallpaperAnimLayerAdjustment =
+ (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null)
+ ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+
if (mWallpaperTarget.mWallpaperX >= 0) {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
@@ -700,14 +583,10 @@
}
}
- final boolean changed = updateWallpaperWindowsPlacement(
- windows, wallpaperTarget, wallpaperTargetIndex, visible);
+ updateWallpaperTokens(visible);
- if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
- + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
- + mUpperWallpaperTarget);
-
- return changed;
+ if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
+ + " prev=" + mPrevWallpaperTarget);
}
boolean processWallpaperDrawPendingTimeout() {
@@ -725,7 +604,7 @@
boolean wallpaperReady = true;
for (int curTokenIndex = mWallpaperTokens.size() - 1;
curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
- final WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex);
if (token.hasVisibleNotDrawnWallpaper()) {
// We've told this wallpaper to be visible, but it is not drawn yet
wallpaperReady = false;
@@ -773,23 +652,22 @@
}
if (adjust) {
- dc.adjustWallpaperWindows();
+ adjustWallpaperWindows(dc);
}
}
- void addWallpaperToken(WindowToken token) {
+ void addWallpaperToken(WallpaperWindowToken token) {
mWallpaperTokens.add(token);
}
- void removeWallpaperToken(WindowToken token) {
+ void removeWallpaperToken(WallpaperWindowToken token) {
mWallpaperTokens.remove(token);
}
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
- if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
- pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
- pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
+ if (mPrevWallpaperTarget != null) {
+ pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget);
}
pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
@@ -825,26 +703,28 @@
/** Helper class for storing the results of a wallpaper target find operation. */
final private static class FindWallpaperTargetResult {
- int topWallpaperIndex = 0;
WindowState topWallpaper = null;
- int wallpaperTargetIndex = 0;
+ boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
+ boolean resetTopWallpaper = false;
- void setTopWallpaper(WindowState win, int index) {
+ void setTopWallpaper(WindowState win) {
topWallpaper = win;
- topWallpaperIndex = index;
}
- void setWallpaperTarget(WindowState win, int index) {
+ void setWallpaperTarget(WindowState win) {
wallpaperTarget = win;
- wallpaperTargetIndex = index;
+ }
+
+ void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) {
+ useTopWallpaperAsTarget = topWallpaperAsTarget;
}
void reset() {
- topWallpaperIndex = 0;
topWallpaper = null;
- wallpaperTargetIndex = 0;
wallpaperTarget = null;
+ useTopWallpaperAsTarget = false;
+ resetTopWallpaper = false;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
new file mode 100644
index 0000000..8ea1b3b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.animation.Animation;
+
+/**
+ * A token that represents a set of wallpaper windows.
+ */
+class WallpaperWindowToken extends WindowToken {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
+
+ WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
+ DisplayContent dc) {
+ super(service, token, TYPE_WALLPAPER, explicit, dc);
+ dc.mWallpaperController.addWallpaperToken(this);
+ }
+
+ @Override
+ void setExiting() {
+ super.setExiting();
+ mDisplayContent.mWallpaperController.removeWallpaperToken(this);
+ }
+
+ void hideWallpaperToken(boolean wasDeferred, String reason) {
+ for (int j = mChildren.size() - 1; j >= 0; j--) {
+ final WindowState wallpaper = mChildren.get(j);
+ wallpaper.hideWallpaperWindow(wasDeferred, reason);
+ }
+ hidden = true;
+ }
+
+ void sendWindowWallpaperCommand(
+ String action, int x, int y, int z, Bundle extras, boolean sync) {
+ for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ final WindowState wallpaper = mChildren.get(wallpaperNdx);
+ try {
+ wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync);
+ // We only want to be synchronous with one wallpaper.
+ sync = false;
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ void updateWallpaperOffset(int dw, int dh, boolean sync) {
+ final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ final WindowState wallpaper = mChildren.get(wallpaperNdx);
+ if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
+ final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+ winAnimator.computeShownFrameLocked();
+ // No need to lay out the windows - we can just set the wallpaper position directly.
+ winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
+ // We only want to be synchronous with one wallpaper.
+ sync = false;
+ }
+ }
+ }
+
+ void updateWallpaperVisibility(boolean visible) {
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
+
+ if (hidden == visible) {
+ hidden = !visible;
+ // Need to do a layout to ensure the wallpaper now has the correct size.
+ mDisplayContent.setLayoutNeeded();
+ }
+
+ final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ final WindowState wallpaper = mChildren.get(wallpaperNdx);
+ if (visible) {
+ wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
+ }
+
+ wallpaper.dispatchWallpaperVisibility(visible);
+ }
+ }
+
+ /**
+ * Starts {@param anim} on all children.
+ */
+ void startAnimation(Animation anim) {
+ for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
+ final WindowState windowState = mChildren.get(ndx);
+ windowState.mWinAnimator.setAnimation(anim);
+ }
+ }
+
+ void updateWallpaperWindows(boolean visible, int animLayerAdj) {
+
+ if (hidden == visible) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
+ "Wallpaper token " + token + " hidden=" + !visible);
+ hidden = !visible;
+ // Need to do a layout to ensure the wallpaper now has the correct size.
+ mDisplayContent.setLayoutNeeded();
+ }
+
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
+ final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+ final WindowState wallpaper = mChildren.get(wallpaperNdx);
+
+ if (visible) {
+ wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
+ }
+
+ // First, make sure the client has the current visibility state.
+ wallpaper.dispatchWallpaperVisibility(visible);
+ wallpaper.adjustAnimLayer(animLayerAdj);
+
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
+ }
+ }
+
+ boolean hasVisibleNotDrawnWallpaper() {
+ for (int j = mChildren.size() - 1; j >= 0; --j) {
+ final WindowState wallpaper = mChildren.get(j);
+ if (wallpaper.hasVisibleNotDrawnWallpaper()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ if (stringName == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("WallpaperWindowToken{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" token="); sb.append(token); sb.append('}');
+ stringName = sb.toString();
+ }
+ return stringName;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e30ebcb..a6a907c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -19,9 +19,13 @@
import android.annotation.CallSuper;
import android.content.res.Configuration;
import android.view.animation.Animation;
+import com.android.internal.util.ToBooleanFunction;
import java.util.Comparator;
import java.util.LinkedList;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -495,6 +499,51 @@
}
/**
+ * For all windows at or below this container call the callback.
+ * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
+ * stops the search if {@link ToBooleanFunction#apply} returns true.
+ * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
+ * z-order, else from bottom-to-top.
+ * @return True if the search ended before we reached the end of the hierarchy due to
+ * {@link Function#apply} returning true.
+ */
+ boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
+ forAllWindows(w -> {
+ callback.accept(w);
+ return false;
+ }, traverseTopToBottom);
+ }
+
+ WindowState getWindow(Predicate<WindowState> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowState w = mChildren.get(i).getWindow(callback);
+ if (w != null) {
+ return w;
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
* the input container in terms of z-order.
*/
@@ -562,8 +611,7 @@
void dumpChildrenNames(StringBuilder out, String prefix) {
final String childPrefix = prefix + " ";
out.append(getName() + "\n");
- final int count = mChildren.size();
- for (int i = 0; i < count; i++) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
out.append(childPrefix + "#" + i + " ");
wc.dumpChildrenNames(out, childPrefix);
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index d94094a..32373f9 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -23,6 +23,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -60,69 +61,74 @@
private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
private WindowState mDockDivider = null;
private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
+ private int mCurBaseLayer;
+ private int mCurLayer;
+ private boolean mAnyLayerChanged;
+ private int mHighestLayerInImeTargetBaseLayer;
+ private WindowState mImeTarget;
- final void assignWindowLayers(ReadOnlyWindowList windows) {
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
+ final void assignWindowLayers(DisplayContent dc) {
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based",
new RuntimeException("here").fillInStackTrace());
- clear();
- int curBaseLayer = 0;
- int curLayer = 0;
- boolean anyLayerChanged = false;
- for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
- final WindowState w = windows.get(i);
+ reset();
+ dc.forAllWindows((w) -> {
boolean layerChanged = false;
int oldLayer = w.mLayer;
- if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
- curLayer += WINDOW_LAYER_MULTIPLIER;
+ if (w.mBaseLayer == mCurBaseLayer) {
+ mCurLayer += WINDOW_LAYER_MULTIPLIER;
} else {
- curBaseLayer = curLayer = w.mBaseLayer;
+ mCurBaseLayer = mCurLayer = w.mBaseLayer;
}
- assignAnimLayer(w, curLayer);
+ assignAnimLayer(w, mCurLayer);
- // TODO: Preserved old behavior of code here but not sure comparing
- // oldLayer to mAnimLayer and mLayer makes sense...though the
- // worst case would be unintentional layer reassignment.
+ // TODO: Preserved old behavior of code here but not sure comparing oldLayer to
+ // mAnimLayer and mLayer makes sense...though the worst case would be unintentional
+ // layer reassignment.
if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
layerChanged = true;
- anyLayerChanged = true;
+ mAnyLayerChanged = true;
}
if (w.mAppToken != null) {
mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
w.mWinAnimator.mAnimLayer);
}
+ if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) {
+ mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
+ w.mWinAnimator.mAnimLayer);
+ }
+
collectSpecialWindows(w);
if (layerChanged) {
w.scheduleAnimationIfDimming();
}
- }
+ }, false /* traverseTopToBottom */);
adjustSpecialWindows();
//TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mAccessibilityController != null && anyLayerChanged
- && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
+ if (mService.mAccessibilityController != null && mAnyLayerChanged
+ && dc.getDisplayId() == DEFAULT_DISPLAY) {
mService.mAccessibilityController.onWindowLayersChangedLocked();
}
- if (DEBUG_LAYERS) logDebugLayers(windows);
+ if (DEBUG_LAYERS) logDebugLayers(dc);
}
- private void logDebugLayers(ReadOnlyWindowList windows) {
- for (int i = 0, n = windows.size(); i < n; i++) {
- final WindowState w = windows.get(i);
+ private void logDebugLayers(DisplayContent dc) {
+ dc.forAllWindows((w) -> {
final WindowStateAnimator winAnimator = w.mWinAnimator;
Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
+ " mLayer=" + w.mLayer + (w.mAppToken == null
? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ " =mAnimLayer=" + winAnimator.mAnimLayer);
- }
+ }, false /* traverseTopToBottom */);
}
- private void clear() {
+ private void reset() {
mHighestApplicationLayer = 0;
mPinnedWindows.clear();
mInputMethodWindows.clear();
@@ -130,6 +136,13 @@
mOnTopLauncherWindows.clear();
mReplacingWindows.clear();
mDockDivider = null;
+
+ mCurBaseLayer = 0;
+ mCurLayer = 0;
+ mAnyLayerChanged = false;
+
+ mImeTarget = mService.mInputMethodTarget;
+ mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
}
private void collectSpecialWindows(WindowState w) {
@@ -172,22 +185,10 @@
layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
- boolean onTopLauncherVisible = !mOnTopLauncherWindows.isEmpty();
while (!mOnTopLauncherWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
}
- // Make sure IME windows are showing above the dock divider and on-top launcher windows.
- if ((mDockDivider != null && mDockDivider.isVisibleLw()) || onTopLauncherVisible) {
- while (!mInputMethodWindows.isEmpty()) {
- final WindowState w = mInputMethodWindows.remove();
- // Only ever move IME windows up, else we brake IME for windows above the divider.
- if (layer > w.mLayer) {
- layer = assignAndIncreaseLayerIfNeeded(w, layer);
- }
- }
- }
-
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
// treatment, e.g. to be above the dock divider.
@@ -198,12 +199,26 @@
while (!mPinnedWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
}
+
+ // Make sure IME is the highest window in the base layer of it's target.
+ if (mImeTarget != null) {
+ if (mImeTarget.mAppToken == null) {
+ // For non-app ime targets adjust the layer we start from to match what we found
+ // when assigning layers. Otherwise, just use the highest app layer we have some far.
+ layer = mHighestLayerInImeTargetBaseLayer + WINDOW_LAYER_MULTIPLIER;
+ }
+
+ while (!mInputMethodWindows.isEmpty()) {
+ layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer);
+ }
+ }
+
}
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
if (win != null) {
assignAnimLayer(win, layer);
- // Make sure we leave space inbetween normal windows for dims and such.
+ // Make sure we leave space in-between normal windows for dims and such.
layer += WINDOW_LAYER_MULTIPLIER;
}
return layer;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a533d84..00d8fba 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.Notification;
@@ -172,7 +171,6 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -1019,7 +1017,7 @@
mBoundsAnimationController =
new BoundsAnimationController(mAppTransition, UiThread.getHandler());
- mActivityManager = ActivityManagerNative.getDefault();
+ mActivityManager = ActivityManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
AppOpsManager.OnOpChangedInternalListener opListener =
@@ -2415,9 +2413,10 @@
+ " displayId=" + displayId);
return;
}
- token = new WindowToken(this, binder, type, true, dc);
if (type == TYPE_WALLPAPER) {
- dc.mWallpaperController.addWallpaperToken(token);
+ new WallpaperWindowToken(this, binder, true, dc);
+ } else {
+ new WindowToken(this, binder, type, true, dc);
}
}
}
@@ -2446,9 +2445,6 @@
}
token.setExiting();
- if (token.windowType == TYPE_WALLPAPER) {
- dc.mWallpaperController.removeWallpaperToken(token);
- }
mInputMonitor.updateInputWindowsLw(true /*force*/);
}
@@ -3404,7 +3400,7 @@
public Rect getPictureInPictureDefaultBounds(int displayId) {
synchronized (mWindowMap) {
if (!mSupportsPictureInPicture) {
- return new Rect();
+ return null;
}
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -3416,7 +3412,7 @@
public Rect getPictureInPictureMovementBounds(int displayId) {
synchronized (mWindowMap) {
if (!mSupportsPictureInPicture) {
- return new Rect();
+ return null;
}
final Rect stackBounds = new Rect();
@@ -3430,6 +3426,47 @@
}
}
+ public void setPictureInPictureAspectRatio(float aspectRatio) {
+ synchronized (mWindowMap) {
+ if (!mSupportsPictureInPicture) {
+ return;
+ }
+
+ final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+ if (stack == null) {
+ return;
+ }
+
+ animateResizePinnedStack(getPictureInPictureBounds(
+ stack.getDisplayContent().getDisplayId(), aspectRatio), -1);
+ }
+ }
+
+ public Rect getPictureInPictureBounds(int displayId, float aspectRatio) {
+ synchronized (mWindowMap) {
+ if (!mSupportsPictureInPicture) {
+ return null;
+ }
+
+ final Rect stackBounds;
+ final DisplayContent displayContent;
+ final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+ if (stack != null) {
+ // If the stack exists, then use its final bounds to calculate the new aspect ratio
+ // bounds.
+ displayContent = stack.getDisplayContent();
+ stackBounds = new Rect();
+ stack.getAnimatingBounds(stackBounds);
+ } else {
+ // Otherwise, just calculate the aspect ratio bounds from the default bounds
+ displayContent = mRoot.getDisplayContent(displayId);
+ stackBounds = displayContent.getPinnedStackController().getDefaultBounds();
+ }
+ return displayContent.getPinnedStackController().getAspectRatioBounds(stackBounds,
+ aspectRatio);
+ }
+ }
+
/**
* Place a TaskStack on a DisplayContent. Will create a new TaskStack if none is found with
* specified stackId.
@@ -3578,6 +3615,11 @@
notifyKeyguardFlagsChanged(null /* callback */);
}
+ @Override
+ public void notifyKeyguardTrustedChanged() {
+ mH.sendEmptyMessage(H.NOTIFY_KEYGUARD_TRUSTED_CHANGED);
+ }
+
/**
* Re-sizes a stack and its containing tasks.
* @param stackId Id of stack to resize.
@@ -4744,37 +4786,42 @@
return false;
}
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- final ReadOnlyWindowList windows = displayContent.getReadOnlyWindowList();
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
final int oldRotation = mRotation;
int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
- boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
+ final boolean rotateSeamlessly;
- if (rotateSeamlessly) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState w = windows.get(i);
+ if (mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
+ final WindowState seamlessRotated = dc.getWindow((w) -> w.mSeamlesslyRotated);
+ if (seamlessRotated != null) {
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
// to complete (that is, waiting for windows to redraw). It's tempting to check
- // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
- if (w.mSeamlesslyRotated) {
- return false;
- }
- // In what can only be called an unfortunate workaround we require
- // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
- // flag. Due to limitations in the client API, there is no way for
- // the client to set this flag in a race free fashion. If we seamlessly rotate
- // a window which does not have this flag, but then gains it, we will get
- // an incorrect visual result (rotated viewfinder). This means if we want to
- // support seamlessly rotating windows which could gain this flag, we can't
- // rotate windows without it. This limits seamless rotation in N to camera framework
- // users, windows without children, and native code. This is unfortunate but
- // having the camera work is our primary goal.
- if (w.isChildWindow() & w.isVisibleNow() &&
- !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
- rotateSeamlessly = false;
- }
+ // w.mSeamlessRotationCount but that could be incorrect in the case of
+ // window-removal.
+ return false;
}
+
+ final WindowState cantSeamlesslyRotate = dc.getWindow((w) ->
+ w.isChildWindow() && w.isVisibleNow()
+ && !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
+ if (cantSeamlesslyRotate != null) {
+ // In what can only be called an unfortunate workaround we require seamlessly
+ // rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE flag. Due to
+ // limitations in the client API, there is no way for the client to set this flag in
+ // a race free fashion. If we seamlessly rotate a window which does not have this
+ // flag, but then gains it, we will get an incorrect visual result
+ // (rotated viewfinder). This means if we want to support seamlessly rotating
+ // windows which could gain this flag, we can't rotate windows without it. This
+ // limits seamless rotation in N to camera framework users, windows without
+ // children, and native code. This is unfortunate but having the camera work is our
+ // primary goal.
+ rotateSeamlessly = false;
+ } else {
+ rotateSeamlessly = true;
+ }
+ } else {
+ rotateSeamlessly = false;
}
// TODO: Implement forced rotation changes.
@@ -4806,9 +4853,9 @@
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
mWaitingForConfig = true;
- displayContent.setLayoutNeeded();
+ dc.setLayoutNeeded();
final int[] anim = new int[2];
- if (displayContent.isDimming()) {
+ if (dc.isDimming()) {
anim[0] = anim[1] = 0;
} else {
mPolicy.selectRotationAnimationLw(anim);
@@ -4817,8 +4864,7 @@
if (!rotateSeamlessly) {
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
- screenRotationAnimation =
- mAnimator.getScreenRotationAnimationLocked(displayId);
+ screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId);
} else {
// The screen rotation animation uses a screenshot to freeze the screen
// while windows resize underneath.
@@ -4836,9 +4882,9 @@
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
// By updating the Display info here it will be available to
// computeScreenConfigurationLocked later.
- updateDisplayAndOrientationLocked(displayContent.getConfiguration().uiMode, displayId);
+ updateDisplayAndOrientationLocked(dc.getConfiguration().uiMode, displayId);
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = dc.getDisplayInfo();
if (!inTransaction) {
if (SHOW_TRANSACTIONS) {
Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
@@ -4859,10 +4905,9 @@
}
if (rotateSeamlessly) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState w = windows.get(i);
- w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
- }
+ dc.forAllWindows(w -> {
+ w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
+ }, true /* traverseTopToBottom */);
}
mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
@@ -4875,8 +4920,7 @@
}
}
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState w = windows.get(i);
+ dc.forAllWindows(w -> {
// Discard surface after orientation change, these can't be reused.
if (w.mAppToken != null) {
w.mAppToken.destroySavedSurfaces();
@@ -4887,7 +4931,8 @@
mRoot.mOrientationChangeComplete = false;
w.mLastFreezeDuration = 0;
}
- }
+
+ }, true /* traverseTopToBottom */);
if (rotateSeamlessly) {
mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
@@ -4905,7 +4950,7 @@
// Announce rotation only if we will not animate as we already have the
// windows in final state. Otherwise, we make this call at the rotation end.
if (screenRotationAnimation == null && mAccessibilityController != null
- && displayContent.getDisplayId() == DEFAULT_DISPLAY) {
+ && dc.getDisplayId() == DEFAULT_DISPLAY) {
mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(),
rotation);
}
@@ -5138,7 +5183,9 @@
final WindowList windows = new WindowList();
synchronized (mWindowMap) {
- mRoot.getWindows(windows);
+ mRoot.forAllWindows(w -> {
+ windows.add(w);
+ }, false /* traverseTopToBottom */);
}
BufferedWriter out = null;
@@ -5365,7 +5412,7 @@
}
synchronized (mWindowMap) {
- return mRoot.findWindow(hashCode);
+ return mRoot.getWindow((w) -> System.identityHashCode(w) == hashCode);
}
}
@@ -5411,17 +5458,16 @@
return config;
}
- private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int uiMode,
- int dw, int dh) {
- // TODO: Multidisplay: for now only use with default display.
- final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode);
+ private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
+ int uiMode, int dw, int dh) {
+ final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode, displayId);
if (width < displayInfo.smallestNominalAppWidth) {
displayInfo.smallestNominalAppWidth = width;
}
if (width > displayInfo.largestNominalAppWidth) {
displayInfo.largestNominalAppWidth = width;
}
- final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode);
+ final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode, displayId);
if (height < displayInfo.smallestNominalAppHeight) {
displayInfo.smallestNominalAppHeight = height;
}
@@ -5431,11 +5477,10 @@
}
private int reduceConfigLayout(int curLayout, int rotation, float density,
- int dw, int dh, int uiMode) {
- // TODO: Multidisplay: for now only use with default display.
+ int dw, int dh, int uiMode, int displayId) {
// Get the app screen size at this rotation.
- int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode);
- int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode);
+ int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
+ int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
// Compute the screen layout size class for this rotation.
int longSize = w;
@@ -5450,9 +5495,8 @@
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
}
- private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
- int uiMode, int dw, int dh, float density, Configuration outConfig) {
- // TODO: Multidisplay: for now only use with default display.
+ private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
+ boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
// We need to determine the smallest width that will occur under normal
// operation. To this, start with the base screen size and compute the
@@ -5470,24 +5514,33 @@
displayInfo.smallestNominalAppHeight = 1<<30;
displayInfo.largestNominalAppWidth = 0;
displayInfo.largestNominalAppHeight = 0;
- adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh);
- adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw);
- adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh);
- adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw);
+ adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
+ unrotDh);
+ adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
+ unrotDw);
+ adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
+ unrotDh);
+ adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
+ unrotDw);
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
- sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode);
- sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode);
- sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode);
- sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
+ displayId);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
+ displayId);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
+ displayId);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
+ displayId);
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
outConfig.screenLayout = sl;
}
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
- DisplayMetrics dm, int dw, int dh) {
- // TODO: Multidisplay: for now only use with default display.
- dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode);
- dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode);
+ DisplayMetrics dm, int dw, int dh, int displayId) {
+ dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
+ displayId);
+ dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
+ displayId);
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
if (curSize == 0 || size < curSize) {
@@ -5496,8 +5549,8 @@
return curSize;
}
- private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, int dh) {
- // TODO: Multidisplay: for now only use with default display.
+ private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw,
+ int dh, int displayId) {
mTmpDisplayMetrics.setTo(dm);
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
final int unrotDw, unrotDh;
@@ -5508,10 +5561,14 @@
unrotDw = dw;
unrotDh = dh;
}
- int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh);
- sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw);
- sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh);
- sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw);
+ int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
+ displayId);
+ sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
+ displayId);
+ sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
+ displayId);
+ sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
+ displayId);
return sw;
}
@@ -5546,8 +5603,9 @@
}
// Update application display metrics.
- final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode);
- final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode);
+ final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode, displayId);
+ final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
+ displayId);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
displayInfo.rotation = mRotation;
displayInfo.logicalWidth = dw;
@@ -5586,15 +5644,15 @@
config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
Configuration.ORIENTATION_LANDSCAPE;
config.screenWidthDp =
- (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode) /
+ (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode, displayId) /
mDisplayMetrics.density);
config.screenHeightDp =
- (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode) /
+ (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode, displayId) /
mDisplayMetrics.density);
final boolean rotated = (mRotation == Surface.ROTATION_90
|| mRotation == Surface.ROTATION_270);
- computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh,
+ computeSizeRangesAndScreenLayout(displayInfo, displayId, rotated, config.uiMode, dw, dh,
mDisplayMetrics.density, config);
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
@@ -5605,7 +5663,7 @@
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode,
- mDisplayMetrics, dw, dh);
+ mDisplayMetrics, dw, dh, displayId);
config.densityDpi = displayInfo.logicalDensityDpi;
// Update the configuration based on available input devices, lid switch,
@@ -6116,6 +6174,7 @@
public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
public static final int RESTORE_POINTER_ICON = 55;
public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
+ public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
/**
* Used to denote that an integer field in a message will not be used.
@@ -6754,6 +6813,11 @@
case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
mAmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj);
}
+ break;
+ case NOTIFY_KEYGUARD_TRUSTED_CHANGED: {
+ mAmInternal.notifyKeyguardTrustedChanged();
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
@@ -8042,7 +8106,12 @@
mRoot.dumpDisplayContents(pw);
}
- mRoot.getWindows(windows, visibleOnly, appsOnly);
+ mRoot.forAllWindows((w) -> {
+ if ((!visibleOnly || w.mWinAnimator.getShown())
+ && (!appsOnly || w.mAppToken != null)) {
+ windows.add(w);
+ }
+ }, true /* traverseTopToBottom */);
}
} else {
synchronized(mWindowMap) {
@@ -8203,6 +8272,8 @@
StringBuilder output = new StringBuilder();
mRoot.dumpChildrenNames(output, " ");
pw.println(output.toString());
+ pw.println(" ");
+ mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */);
}
return;
} else {
@@ -8456,6 +8527,7 @@
}
final Rect originalBounds = new Rect();
stack.getBounds(originalBounds);
+ stack.setAnimatingBounds(bounds);
UiThread.getHandler().post(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 972c359..661df9cd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -53,12 +53,16 @@
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputWindowHandle;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -137,52 +141,6 @@
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
class WindowList extends ArrayList<WindowState> {
-
- /**
- * Read-only interface for the window list that the creator of the window list can pass-out to
- * other users to prevent them from modifying the window list.
- */
- private ReadOnlyWindowList mReadOnly;
-
- WindowList() {
- mReadOnly = new ReadOnlyWindowList(this);
- }
-
- /** Returns the read-only interface for this window list. */
- ReadOnlyWindowList getReadOnly() {
- return mReadOnly;
- }
-}
-
-/**
- * Read-only interface for a list of windows. It is common for the owner of a list of windows to
- * want to provide a way for external classes to iterate of its windows, but prevent them from
- * modifying the list in any way. This call provides a way for them to do that by wrapping the
- * original window list and only exposing the read-only APIs.
- */
-final class ReadOnlyWindowList {
- // List of windows this read-only class is tied to.
- private final WindowList mWindows;
-
- ReadOnlyWindowList(WindowList windows) {
- mWindows = windows;
- }
-
- WindowState get(int index) {
- return mWindows.get(index);
- }
-
- int indexOf(WindowState w) {
- return mWindows.indexOf(w);
- }
-
- int size() {
- return mWindows.size();
- }
-
- boolean isEmpty() {
- return mWindows.isEmpty();
- }
}
/** A window in the window manager. */
@@ -488,7 +446,7 @@
* or some other higher level component said so (e.g. activity manager).
* TODO: We should either have different booleans for the removal reason or use a bit-field.
*/
- private boolean mWindowRemovalAllowed;
+ boolean mWindowRemovalAllowed;
/**
* Temp for keeping track of windows that have been removed when
@@ -1399,7 +1357,7 @@
* being visible.
*/
boolean isOnScreen() {
- if (!mHasSurface || mDestroying) {
+ if (!mHasSurface || mDestroying || !mPolicyVisibility) {
return false;
}
final AppWindowToken atoken = mAppToken;
@@ -1947,9 +1905,7 @@
}
int getAnimLayerAdjustment() {
- final boolean isImeType =
- mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
- if (isImeType && mService.mInputMethodTarget != null) {
+ if (mIsImWindow && mService.mInputMethodTarget != null) {
final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
if (appToken != null) {
return appToken.mAppAnimator.animLayerAdjustment;
@@ -3876,6 +3832,100 @@
return index;
}
+ @Override
+ boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
+ if (mChildren.isEmpty()) {
+ // The window has no children so we just return it.
+ return callback.apply(this);
+ }
+
+ if (traverseTopToBottom) {
+ return forAllWindowTopToBottom(callback);
+ } else {
+ return forAllWindowBottomToTop(callback);
+ }
+ }
+
+ private boolean forAllWindowBottomToTop(ToBooleanFunction<WindowState> callback) {
+ // We want to consumer the negative sublayer children first because they need to appear
+ // below the parent, then this window (the parent), and then the positive sublayer children
+ // because they need to appear above the parent.
+ int i = 0;
+ final int count = mChildren.size();
+ WindowState child = mChildren.get(i);
+
+ while (i < count && child.mSubLayer < 0) {
+ if (callback.apply(child)) {
+ return true;
+ }
+ i++;
+ if (i >= count) {
+ break;
+ }
+ child = mChildren.get(i);
+ }
+
+ if (callback.apply(this)) {
+ return true;
+ }
+
+ while (i < count) {
+ if (callback.apply(child)) {
+ return true;
+ }
+ i++;
+ if (i >= count) {
+ break;
+ }
+ child = mChildren.get(i);
+ }
+
+ return false;
+ }
+
+ private boolean forAllWindowTopToBottom(ToBooleanFunction<WindowState> callback) {
+ // We want to consumer the positive sublayer children first because they need to appear
+ // above the parent, then this window (the parent), and then the negative sublayer children
+ // because they need to appear above the parent.
+ int i = mChildren.size() - 1;
+ WindowState child = mChildren.get(i);
+
+ while (i >= 0 && child.mSubLayer >= 0) {
+ if (callback.apply(child)) {
+ return true;
+ }
+ --i;
+ if (i < 0) {
+ break;
+ }
+ child = mChildren.get(i);
+ }
+
+ if (callback.apply(this)) {
+ return true;
+ }
+
+ while (i >= 0) {
+ if (callback.apply(child)) {
+ return true;
+ }
+ --i;
+ if (i < 0) {
+ break;
+ }
+ child = mChildren.get(i);
+ }
+
+ return false;
+ }
+
+ WindowState getWindow(Predicate<WindowState> callback) {
+ if (callback.test(this)) {
+ return this;
+ }
+ return super.getWindow(callback);
+ }
+
boolean isWindowAnimationSet() {
if (mWinAnimator.isWindowAnimationSet()) {
return true;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index f2682ba..7e1880f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -266,21 +266,9 @@
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent,
mService.mOpeningApps);
- final WindowState lowerWallpaperTarget =
- mWallpaperControllerLocked.getLowerWallpaperTarget();
- final WindowState upperWallpaperTarget =
- mWallpaperControllerLocked.getUpperWallpaperTarget();
-
+ final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
boolean openingAppHasWallpaper = false;
boolean closingAppHasWallpaper = false;
- final AppWindowToken lowerWallpaperAppToken;
- final AppWindowToken upperWallpaperAppToken;
- if (lowerWallpaperTarget == null) {
- lowerWallpaperAppToken = upperWallpaperAppToken = null;
- } else {
- lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
- upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
- }
// Do a first pass through the tokens for two things:
// (1) Determine if both the closing and opening app token sets are wallpaper targets, in
@@ -294,12 +282,12 @@
final AppWindowToken wtoken;
if (i < closingAppsCount) {
wtoken = mService.mClosingApps.valueAt(i);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) {
closingAppHasWallpaper = true;
}
} else {
wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) {
openingAppHasWallpaper = true;
}
}
@@ -307,14 +295,14 @@
voiceInteraction |= wtoken.voiceInteraction;
if (wtoken.fillsParent()) {
- WindowState ws = wtoken.findMainWindow();
+ final WindowState ws = wtoken.findMainWindow();
if (ws != null) {
animLp = ws.mAttrs;
bestAnimLayer = ws.mLayer;
fullscreenAnim = true;
}
} else if (!fullscreenAnim) {
- WindowState ws = wtoken.findMainWindow();
+ final WindowState ws = wtoken.findMainWindow();
if (ws != null) {
if (ws.mLayer > bestAnimLayer) {
animLp = ws.mAttrs;
@@ -325,7 +313,7 @@
}
transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
- closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
+ closingAppHasWallpaper);
// If all closing windows are obscured, then there is no need to do an animation. This is
// the case, for example, when this transition is being done behind the lock screen.
@@ -578,8 +566,7 @@
}
private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
- boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
- WindowState upperWallpaperTarget) {
+ boolean closingAppHasWallpaper) {
// if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
@@ -590,8 +577,6 @@
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + wallpaperTarget
+ ", oldWallpaper=" + oldWallpaper
- + ", lower target=" + lowerWallpaperTarget
- + ", upper target=" + upperWallpaperTarget
+ ", openingApps=" + openingApps
+ ", closingApps=" + closingApps);
mService.mAnimateWallpaperWithTarget = false;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index b821f09..a2eebc3 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -82,7 +82,7 @@
boolean sendingToBottom;
// The display this token is on.
- private DisplayContent mDisplayContent;
+ protected DisplayContent mDisplayContent;
/**
* Compares two child window of this token and returns -1 if the first is lesser than the
@@ -176,29 +176,13 @@
}
/**
- * Recursive search through a WindowList and all of its windows' children.
- * @param target The window to search for.
- * @return The index of win in windows or of the window that is an ancestor of win.
- */
- int getWindowIndex(WindowState target) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState w = mChildren.get(i);
- if (w == target || w.hasChild(target)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
*/
protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
WindowState existingWindow) {
- // By default the first window isn't greater than the second to preserve existing logic of
- // how new windows are added to the token
- return false;
+ // New window is considered greater if it has a higher or equal base layer.
+ return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
}
void addWindow(final WindowState win) {
@@ -280,169 +264,6 @@
return false;
}
- void hideWallpaperToken(boolean wasDeferred, String reason) {
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final WindowState wallpaper = mChildren.get(j);
- wallpaper.hideWallpaperWindow(wasDeferred, reason);
- }
- hidden = true;
- }
-
- void sendWindowWallpaperCommand(
- String action, int x, int y, int z, Bundle extras, boolean sync) {
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
- try {
- wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync);
- // We only want to be synchronous with one wallpaper.
- sync = false;
- } catch (RemoteException e) {
- }
- }
- }
-
- void updateWallpaperOffset(int dw, int dh, boolean sync) {
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
- if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
- final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- winAnimator.computeShownFrameLocked();
- // No need to lay out the windows - we can just set the wallpaper position directly.
- winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
- // We only want to be synchronous with one wallpaper.
- sync = false;
- }
- }
- }
-
- void updateWallpaperVisibility(boolean visible) {
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
-
- if (hidden == visible) {
- hidden = !visible;
- // Need to do a layout to ensure the wallpaper now has the correct size.
- mDisplayContent.setLayoutNeeded();
- }
-
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
- if (visible) {
- wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
- }
-
- wallpaper.dispatchWallpaperVisibility(visible);
- }
- }
-
- /**
- * Starts {@param anim} on all children.
- */
- void startAnimation(Animation anim) {
- for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
- final WindowState windowState = mChildren.get(ndx);
- windowState.mWinAnimator.setAnimation(anim);
- }
- }
-
- boolean updateWallpaperWindowsPlacement(ReadOnlyWindowList windowList,
- WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh,
- int wallpaperAnimLayerAdj) {
-
- boolean changed = false;
- if (hidden == visible) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
- "Wallpaper token " + token + " hidden=" + !visible);
- hidden = !visible;
- // Need to do a layout to ensure the wallpaper now has the correct size.
- mDisplayContent.setLayoutNeeded();
- }
-
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
-
- if (visible) {
- wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
- }
-
- // First, make sure the client has the current visibility state.
- wallpaper.dispatchWallpaperVisibility(visible);
- wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj);
-
- if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
- + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
-
- // First, if this window is at the current index, then all is well.
- if (wallpaper == wallpaperTarget) {
- wallpaperTargetIndex--;
- wallpaperTarget = wallpaperTargetIndex > 0
- ? windowList.get(wallpaperTargetIndex - 1) : null;
- continue;
- }
-
- // The window didn't match... the current wallpaper window,
- // wherever it is, is in the wrong place, so make sure it is not in the list.
- int oldIndex = windowList.indexOf(wallpaper);
- if (oldIndex >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
- "Wallpaper removing at " + oldIndex + ": " + wallpaper);
- mDisplayContent.removeFromWindowList(wallpaper);
- if (oldIndex < wallpaperTargetIndex) {
- wallpaperTargetIndex--;
- }
- }
-
- // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
- // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
- // is currently on screen, i.e. not hidden by policy.
- int insertionIndex = 0;
- if (visible && wallpaperTarget != null) {
- final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
- if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- insertionIndex = Math.min(windowList.indexOf(wallpaperTarget),
- findLowestWindowOnScreen(windowList));
- }
- }
- if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
- || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG,
- "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex);
-
- mDisplayContent.addToWindowList(wallpaper, insertionIndex);
- changed = true;
- }
-
- return changed;
- }
-
- /**
- * @return The index in {@param windows} of the lowest window that is currently on screen and
- * not hidden by the policy.
- */
- private int findLowestWindowOnScreen(ReadOnlyWindowList windowList) {
- final int size = windowList.size();
- for (int index = 0; index < size; index++) {
- final WindowState win = windowList.get(index);
- if (win.isOnScreen()) {
- return index;
- }
- }
- return Integer.MAX_VALUE;
- }
-
- boolean hasVisibleNotDrawnWallpaper() {
- for (int j = mChildren.size() - 1; j >= 0; --j) {
- final WindowState wallpaper = mChildren.get(j);
- if (wallpaper.hasVisibleNotDrawnWallpaper()) {
- return true;
- }
- }
- return false;
- }
-
int getHighestAnimLayer() {
int highest = -1;
for (int j = 0; j < mChildren.size(); j++) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index a4b5e6a..c03a460 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -19,6 +19,7 @@
$(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
$(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \
$(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
$(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
$(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
@@ -37,6 +38,7 @@
frameworks/base/libs/hwui \
frameworks/base/core/jni \
frameworks/native/services \
+ system/core/libappfuse/include \
system/security/keystore/include \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
@@ -44,6 +46,7 @@
LOCAL_SHARED_LIBRARIES += \
libandroid_runtime \
libandroidfw \
+ libappfuse \
libbinder \
libcutils \
liblog \
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
new file mode 100644
index 0000000..2f20ecd
--- /dev/null
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+// Need to use LOGE_EX.
+#define LOG_TAG "AppFuseBridge"
+
+#include <android_runtime/Log.h>
+#include <android-base/logging.h>
+#include <core_jni_helpers.h>
+#include <libappfuse/FuseBridgeLoop.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+namespace {
+
+constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge";
+static jclass appFuseClass;
+static jmethodID appFuseOnMount;
+
+class Callback : public fuse::FuseBridgeLoopCallback {
+ JNIEnv* mEnv;
+ jobject mSelf;
+
+public:
+ Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
+ void OnMount() override {
+ mEnv->CallVoidMethod(mSelf, appFuseOnMount);
+ if (mEnv->ExceptionCheck()) {
+ LOGE_EX(mEnv, nullptr);
+ mEnv->ExceptionClear();
+ }
+ }
+};
+
+jboolean com_android_server_storage_AppFuseBridge_start_loop(
+ JNIEnv* env, jobject self, jint devJavaFd, jint proxyJavaFd) {
+ Callback callback(env, self);
+ return fuse::StartFuseBridgeLoop(devJavaFd, proxyJavaFd, &callback);
+}
+
+const JNINativeMethod methods[] = {
+ {
+ "native_start_loop",
+ "(II)Z",
+ (void *) com_android_server_storage_AppFuseBridge_start_loop
+ }
+};
+
+} // namespace
+
+void register_android_server_storage_AppFuse(JNIEnv* env) {
+ CHECK(env != nullptr);
+
+ appFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+ appFuseOnMount = GetMethodIDOrDie(env, appFuseClass, "onMount", "()V");
+ RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
+}
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index d69c37f..c291ba0 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -28,6 +28,7 @@
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
@@ -83,6 +84,7 @@
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
register_android_server_HardwarePropertiesManagerService(env);
+ register_android_server_storage_AppFuse(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0ea8d4e..543bba66 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -22,7 +22,7 @@
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
-import static com.android.internal.logging.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -38,10 +38,11 @@
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -137,6 +138,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.ParcelableString;
@@ -490,9 +492,12 @@
* to listen for events.
*/
if (Intent.ACTION_USER_STARTED.equals(action)
- && userHandle == mOwners.getDeviceOwnerUserId()
- && isNetworkLoggingEnabledInternal()) {
- setNetworkLoggingActiveInternal(true);
+ && userHandle == mOwners.getDeviceOwnerUserId()) {
+ synchronized (DevicePolicyManagerService.this) {
+ if (isNetworkLoggingEnabledInternalLocked()) {
+ setNetworkLoggingActiveInternal(true);
+ }
+ }
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
&& userHandle == mOwners.getDeviceOwnerUserId()
@@ -1436,6 +1441,10 @@
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
+ PackageManager getPackageManager() {
+ return mContext.getPackageManager();
+ }
+
PowerManagerInternal getPowerManagerInternal() {
return LocalServices.getService(PowerManagerInternal.class);
}
@@ -1450,7 +1459,7 @@
}
IActivityManager getIActivityManager() {
- return ActivityManagerNative.getDefault();
+ return ActivityManager.getService();
}
IPackageManager getIPackageManager() {
@@ -5514,7 +5523,7 @@
final long callingIdentity = mInjector.binderClearCallingIdentity();
try {
- ActivityManagerNative.getDefault().requestBugReport(
+ ActivityManager.getService().requestBugReport(
ActivityManager.BUGREPORT_OPTION_REMOTE);
mRemoteBugreportServiceIsActive.set(true);
@@ -5904,6 +5913,10 @@
}
}
+ boolean isDeviceOwner(ActiveAdmin admin) {
+ return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+ }
+
public boolean isDeviceOwner(ComponentName who, int userId) {
synchronized (this) {
return mOwners.hasDeviceOwner()
@@ -6028,6 +6041,7 @@
}
private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
+ disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
if (admin != null) {
admin.disableCamera = false;
admin.userRestrictions = null;
@@ -6039,7 +6053,6 @@
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
- disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
try {
if (mInjector.getIBackupManager() != null) {
// Reactivate backup service.
@@ -9425,6 +9438,77 @@
}
}
+ @Override
+ public boolean bindDeviceAdminServiceAsUser(
+ @NonNull ComponentName admin, @NonNull IApplicationThread caller,
+ @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent,
+ @NonNull IServiceConnection connection, int flags, @UserIdInt int targetUserId) {
+ if (!mHasFeature) {
+ return false;
+ }
+ Preconditions.checkNotNull(admin);
+ Preconditions.checkNotNull(caller);
+ Preconditions.checkNotNull(serviceIntent);
+ Preconditions.checkNotNull(connection);
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ Preconditions.checkArgument(callingUserId != targetUserId,
+ "target user id must be different from the calling user id");
+
+ synchronized (this) {
+ final ActiveAdmin callingAdmin = getActiveAdminForCallerLocked(admin,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the target user is valid.
+ if (isDeviceOwner(callingAdmin)) {
+ enforceManagedProfile(targetUserId, "Target user must be a managed profile");
+ } else {
+ // Further lock down to profile owner in managed profile.
+ enforceManagedProfile(callingUserId,
+ "Only support profile owner in managed profile.");
+ if (mOwners.getDeviceOwnerUserId() != targetUserId) {
+ throw new SecurityException("Target user must be a device owner.");
+ }
+ }
+ }
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ if (!mUserManager.isSameProfileGroup(callingUserId, targetUserId)) {
+ throw new SecurityException(
+ "Can only bind service across users under the same profile group");
+ }
+ final String targetPackage;
+ synchronized (this) {
+ targetPackage = getOwnerPackageNameForUserLocked(targetUserId);
+ }
+ // STOPSHIP(b/31952368): Add policy to control which packages can talk.
+ if (TextUtils.isEmpty(targetPackage) || !targetPackage.equals(admin.getPackageName())) {
+ throw new SecurityException("Device owner and profile owner must be the same " +
+ "package in order to communicate.");
+ }
+ // Validate and sanitize the incoming service intent.
+ final Intent sanitizedIntent =
+ createCrossUserServiceIntent(serviceIntent, targetPackage);
+ if (sanitizedIntent == null) {
+ // Fail, cannot lookup the target service.
+ throw new SecurityException("Invalid intent or failed to look up the service");
+ }
+ // Ask ActivityManager to bind it. Notice that we are binding the service with the
+ // caller app instead of DevicePolicyManagerService.
+ try {
+ return mInjector.getIActivityManager().bindService(
+ caller, activtiyToken, serviceIntent,
+ serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ connection, flags, mContext.getOpPackageName(),
+ targetUserId) != 0;
+ } catch (RemoteException ex) {
+ // Same process, should not happen.
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ // Fail to bind.
+ return false;
+ }
+
/**
* Return true if a given user has any accounts that'll prevent installing a device or profile
* owner {@code owner}.
@@ -9515,7 +9599,7 @@
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
- if (enabled == isNetworkLoggingEnabledInternal()) {
+ if (enabled == isNetworkLoggingEnabledInternalLocked()) {
// already in the requested state
return;
}
@@ -9556,11 +9640,11 @@
Preconditions.checkNotNull(admin);
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- return isNetworkLoggingEnabledInternal();
+ return isNetworkLoggingEnabledInternalLocked();
}
}
- private synchronized boolean isNetworkLoggingEnabledInternal() {
+ private boolean isNetworkLoggingEnabledInternalLocked() {
ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled;
}
@@ -9569,9 +9653,12 @@
* A maximum of 1200 events are returned, and the total marshalled size is in the order of
* 100kB, so returning a List instead of ParceledListSlice is acceptable.
* Ideally this would be done with ParceledList, however it only supports homogeneous types.
+ *
+ * @see NetworkLoggingHandler#MAX_EVENTS_PER_BATCH
*/
@Override
- public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin) {
+ public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin,
+ long batchToken) {
if (!mHasFeature) {
return null;
}
@@ -9581,6 +9668,50 @@
if (mNetworkLogger == null) {
return null;
}
- return isNetworkLoggingEnabledInternal() ? mNetworkLogger.retrieveLogs() : null;
+ return isNetworkLoggingEnabledInternalLocked()
+ ? mNetworkLogger.retrieveLogs(batchToken)
+ : null;
+ }
+
+ /**
+ * Return the package name of owner in a given user.
+ */
+ private String getOwnerPackageNameForUserLocked(int userId) {
+ return getDeviceOwnerUserId() == userId
+ ? mOwners.getDeviceOwnerPackageName()
+ : mOwners.getProfileOwnerPackage(userId);
+ }
+
+ /**
+ * @param rawIntent Original service intent specified by caller.
+ * @param expectedPackageName The expected package name in the incoming intent.
+ * @return Intent that have component explicitly set. {@code null} if the incoming intent
+ * or target service is invalid.
+ */
+ private Intent createCrossUserServiceIntent (
+ @NonNull Intent rawIntent, @NonNull String expectedPackageName) {
+ if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) {
+ Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): "
+ + rawIntent);
+ return null;
+ }
+ ResolveInfo info = mInjector.getPackageManager().resolveService(rawIntent, 0);
+ if (info == null || info.serviceInfo == null) {
+ Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent);
+ return null;
+ }
+ if (!expectedPackageName.equals(info.serviceInfo.packageName)) {
+ Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName);
+ return null;
+ }
+ if (info.serviceInfo.exported) {
+ Log.e(LOG_TAG, "The service must be unexported.");
+ return null;
+ }
+ // It is the system server to bind the service, it would be extremely dangerous if it
+ // can be exploited to bind any service. Set the component explicitly to make sure we
+ // do not bind anything accidentally.
+ rawIntent.setComponent(info.serviceInfo.getComponentName());
+ return rawIntent;
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 185ccc2..8cb13da 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -147,7 +147,7 @@
}
}
- List<NetworkEvent> retrieveLogs() {
- return mNetworkLoggingHandler.retrieveFullLogBatch();
+ List<NetworkEvent> retrieveLogs(long batchToken) {
+ return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 96884e6..29cc43f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -55,11 +55,16 @@
private final DevicePolicyManagerService mDpm;
// threadsafe as it's Handler's thread confined
+ @GuardedBy("this")
private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>();
@GuardedBy("this")
private ArrayList<NetworkEvent> mFullBatch;
+ // each full batch is represented by its token, which the DPC has to provide back to revieve it
+ @GuardedBy("this")
+ private long mCurrentFullBatchToken;
+
NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) {
super(looper);
mDpm = dpm;
@@ -97,17 +102,21 @@
scheduleBatchFinalization(BATCH_FINALIZATION_TIMEOUT_MS);
// notify DO that there's a new non-empty batch waiting
if (mFullBatch.size() > 0) {
- mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE,
- /* extras */ null);
+ mCurrentFullBatchToken++;
+ Bundle extras = new Bundle();
+ extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentFullBatchToken);
+ extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, mFullBatch.size());
+ mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);
} else {
mFullBatch = null;
}
}
- synchronized List<NetworkEvent> retrieveFullLogBatch() {
- List<NetworkEvent> ret = mFullBatch;
- mFullBatch = null;
- return ret;
+ synchronized List<NetworkEvent> retrieveFullLogBatch(long batchToken) {
+ if (batchToken != mCurrentFullBatchToken) {
+ return null;
+ }
+ return mFullBatch;
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cc96f565..1202025 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.os.BaseBundle;
+import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
@@ -41,7 +42,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.IMountService;
+import android.os.storage.IStorageManager;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -166,8 +167,8 @@
"com.android.server.job.JobSchedulerService";
private static final String LOCK_SETTINGS_SERVICE_CLASS =
"com.android.server.LockSettingsService$Lifecycle";
- private static final String MOUNT_SERVICE_CLASS =
- "com.android.server.MountService$Lifecycle";
+ private static final String STORAGE_MANAGER_SERVICE_CLASS =
+ "com.android.server.StorageManagerService$Lifecycle";
private static final String SEARCH_MANAGER_SERVICE_CLASS =
"com.android.server.search.SearchManagerService$Lifecycle";
private static final String THERMAL_OBSERVER_CLASS =
@@ -184,6 +185,8 @@
"com.android.server.content.ContentService$Lifecycle";
private static final String WALLPAPER_SERVICE_CLASS =
"com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
+ private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
+ "com.android.server.autofill.AutoFillManagerService";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -267,6 +270,9 @@
SystemProperties.set("persist.sys.localevar", "");
}
+ // The system server should never make non-oneway calls
+ Binder.setWarnOnBlocking(true);
+
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
@@ -566,7 +572,7 @@
private void startOtherServices() {
final Context context = mSystemContext;
VibratorService vibrator = null;
- IMountService mountService = null;
+ IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
@@ -778,17 +784,17 @@
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
if (!disableStorage &&
!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
- traceBeginAndSlog("StartMountService");
+ traceBeginAndSlog("StartStorageManagerService");
try {
/*
- * NotificationManagerService is dependant on MountService,
- * (for media / usb notifications) so we must start MountService first.
+ * NotificationManagerService is dependant on StorageManagerService,
+ * (for media / usb notifications) so we must start StorageManagerService first.
*/
- mSystemServiceManager.startService(MOUNT_SERVICE_CLASS);
- mountService = IMountService.Stub.asInterface(
+ mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
+ storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
} catch (Throwable e) {
- reportWtf("starting Mount Service", e);
+ reportWtf("starting StorageManager Service", e);
}
traceEnd();
}
@@ -987,14 +993,14 @@
}
/*
- * MountService has a few dependencies: Notification Manager and
- * AppWidget Provider. Make sure MountService is completely started
+ * StorageManagerService has a few dependencies: Notification Manager and
+ * AppWidget Provider. Make sure StorageManagerService is completely started
* first before continuing.
*/
- if (mountService != null && !mOnlyCore) {
+ if (storageManager != null && !mOnlyCore) {
traceBeginAndSlog("WaitForAsecScan");
try {
- mountService.waitForAsecScan();
+ storageManager.waitForAsecScan();
} catch (RemoteException ignored) {
}
traceEnd();
@@ -1362,6 +1368,10 @@
mSystemServiceManager.startService(RetailDemoModeService.class);
traceEnd();
+ traceBeginAndSlog("StartAutoFillService");
+ mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS);
+ traceEnd();
+
// It is now time to start up the app processes...
traceBeginAndSlog("MakeVibratorServiceReady");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 01d9304..39f14e5 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -631,6 +631,11 @@
return shouldLog;
}
+ // TODO: Migrate all Log.e(...) to logError(...).
+ private void logError(String fmt, Object... args) {
+ mLocalLog.log("ERROR " + String.format(fmt, args));
+ }
+
private void getNetworkInterface() {
try {
mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
@@ -880,7 +885,7 @@
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
if (VDBG) Log.d(mTag, "IPv4 configuration succeeded");
} catch (IllegalStateException | RemoteException e) {
- Log.e(mTag, "IPv4 configuration failed: ", e);
+ logError("IPv4 configuration failed: %s", e);
return false;
}
return true;
@@ -944,6 +949,12 @@
}
}
+ private void doImmediateProvisioningFailure(int failureType) {
+ if (DBG) { Log.e(mTag, "onProvisioningFailure(): " + failureType); }
+ recordMetric(failureType);
+ mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
+ }
+
private boolean startIPv4() {
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
@@ -951,9 +962,6 @@
if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
- if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
- recordMetric(IpManagerEvent.PROVISIONING_FAIL);
- mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
return false;
}
} else {
@@ -972,16 +980,40 @@
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
mNwService.enableIpv6(mInterfaceName);
} catch (RemoteException re) {
- Log.e(mTag, "Unable to change interface settings: " + re);
+ logError("Unable to change interface settings: %s", re);
return false;
} catch (IllegalStateException ie) {
- Log.e(mTag, "Unable to change interface settings: " + ie);
+ logError("Unable to change interface settings: %s", ie);
return false;
}
return true;
}
+ private boolean startIpReachabilityMonitor() {
+ try {
+ mIpReachabilityMonitor = new IpReachabilityMonitor(
+ mContext,
+ mInterfaceName,
+ new IpReachabilityMonitor.Callback() {
+ @Override
+ public void notifyLost(InetAddress ip, String logMsg) {
+ mCallback.onReachabilityLost(logMsg);
+ }
+ },
+ mAvoidBadWifiTracker);
+ } catch (IllegalArgumentException iae) {
+ // Failed to start IpReachabilityMonitor. Log it and call
+ // onProvisioningFailure() immediately.
+ //
+ // See http://b/31038971.
+ logError("IpReachabilityMonitor failure: %s", iae);
+ mIpReachabilityMonitor = null;
+ }
+
+ return (mIpReachabilityMonitor != null);
+ }
+
private void stopAllIP() {
// We don't need to worry about routes, just addresses, because:
// - disableIpv6() will clear autoconf IPv6 routes as well, and
@@ -1165,29 +1197,23 @@
mCallback.setFallbackMulticastFilter(mMulticastFiltering);
}
- if (mConfiguration.mEnableIPv6) {
- // TODO: Consider transitionTo(mStoppingState) if this fails.
- startIPv6();
+ if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+ transitionTo(mStoppingState);
+ return;
}
- if (mConfiguration.mEnableIPv4) {
- if (!startIPv4()) {
- transitionTo(mStoppingState);
- return;
- }
+ if (mConfiguration.mEnableIPv4 && !startIPv4()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
+ transitionTo(mStoppingState);
+ return;
}
- if (mConfiguration.mUsingIpReachabilityMonitor) {
- mIpReachabilityMonitor = new IpReachabilityMonitor(
- mContext,
- mInterfaceName,
- new IpReachabilityMonitor.Callback() {
- @Override
- public void notifyLost(InetAddress ip, String logMsg) {
- mCallback.onReachabilityLost(logMsg);
- }
- },
- mAvoidBadWifiTracker);
+ if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
+ doImmediateProvisioningFailure(
+ IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
+ transitionTo(mStoppingState);
+ return;
}
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 6558b6e..d7666d9 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -22,7 +22,6 @@
import android.Manifest;
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -915,7 +914,7 @@
private int resolveCallingUserEnforcingPermissions(int userId) {
try {
- return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
+ return ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, true, "", null);
} catch (RemoteException re) {
// Shouldn't happen, local.
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 07b26e8..6b919df 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -43,9 +43,12 @@
import android.util.Slog;
import android.util.TimedRemoteCaller;
+import com.android.internal.os.TransferPipe;
+
import libcore.io.IoUtils;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
@@ -572,13 +575,11 @@
.append((mRemoteInstance != null) ? "true" : "false").println();
pw.flush();
-
try {
- getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
- } catch (TimeoutException te) {
- /* ignore */
- } catch (RemoteException re) {
- /* ignore */
+ TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+ new String[] { prefix });
+ } catch (IOException | TimeoutException | RemoteException e) {
+ pw.println("Failed to dump remote instance: " + e);
}
}
}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 65c740f..7474a64 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -68,7 +68,7 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 7c7c299..785c3fa 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -17,8 +17,8 @@
package com.android.server.retaildemo;
import android.Manifest;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Notification;
import android.app.NotificationManager;
@@ -591,7 +591,7 @@
void switchUser(int userId) {
if (mAms == null) {
- mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
+ mAms = (ActivityManagerService) ActivityManager.getService();
}
mAms.switchUser(userId);
}
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 4570a4b..d20e351 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -226,11 +226,11 @@
if (insistent) {
n.flags |= Notification.FLAG_INSISTENT;
}
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
- mScore, n, mUser, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn,
- new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "misc",
- NotificationManager.IMPORTANCE_DEFAULT));
+ NotificationChannel channel =
+ new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_HIGH);
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, id, mTag, mUid,
+ mPid, n, mUser, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn);
mService.addNotification(r);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 22b674b..6c3f447 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -31,6 +31,7 @@
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.UserHandle;
@@ -68,7 +69,10 @@
if (groupKey != null) {
nb.setGroup(groupKey);
}
- return new StatusBarNotification(pkg, pkg, id, tag, 0, 0, 0, nb.build(), user);
+ NotificationChannel channel =
+ new NotificationChannel("test", "test", NotificationManager.IMPORTANCE_LOW);
+ return new StatusBarNotification(pkg, pkg, channel, id, tag, 0, 0, nb.build(), user, null,
+ System.currentTimeMillis());
}
private StatusBarNotification getSbn(String pkg, int id, String tag,
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 305b5e0..6bc9675 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -69,9 +69,9 @@
.setDefaults(Notification.DEFAULT_SOUND);
Notification n = builder.build();
- StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
- mPid, mScore, n, mUser, System.currentTimeMillis());
- NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, channel, mId, mTag, mUid,
+ mPid, n, mUser, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn);
return r;
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 629146f..92c67b5 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -98,8 +98,8 @@
.setWhen(1205)
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user),
- getDefaultChannel());
+ "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortA, user,
+ null, System.currentTimeMillis()));
mNotiGroupGSortB = new Notification.Builder(getContext())
.setContentTitle("B")
@@ -108,24 +108,24 @@
.setWhen(1200)
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user),
- getDefaultChannel());
+ "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiGroupGSortB, user,
+ null, System.currentTimeMillis()));
mNotiNoGroup = new Notification.Builder(getContext())
.setContentTitle("C")
.setWhen(1201)
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user),
- getDefaultChannel());
+ "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup, user,
+ null, System.currentTimeMillis()));
mNotiNoGroup2 = new Notification.Builder(getContext())
.setContentTitle("D")
.setWhen(1202)
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user),
- getDefaultChannel());
+ "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroup2, user,
+ null, System.currentTimeMillis()));
mNotiNoGroupSortA = new Notification.Builder(getContext())
.setContentTitle("E")
@@ -133,8 +133,8 @@
.setSortKey("A")
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user),
- getDefaultChannel());
+ "package", "package", getDefaultChannel(), 1, null, 0, 0, mNotiNoGroupSortA, user,
+ null, System.currentTimeMillis()));
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index ffc45ea..7a3ee7f 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -178,9 +178,13 @@
.setWhen(1205)
.build();
return new NotificationRecord(getContext(), new StatusBarNotification(
- pkg, pkg, id, tag, 0, 0, 0, n, user),
- new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- NotificationManager.IMPORTANCE_HIGH));
+ pkg, pkg, getDefaultChannel(), id, tag, 0, 0, n, user, null,
+ System.currentTimeMillis()));
+ }
+
+ private NotificationChannel getDefaultChannel() {
+ return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
+ NotificationManager.IMPORTANCE_LOW);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
new file mode 100644
index 0000000..d6ee367
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsShellCommandTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+
+import static com.android.internal.widget.LockPatternUtils.stringToPattern;
+
+import static junit.framework.Assert.*;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static java.io.FileDescriptor.*;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+
+/**
+ * Test class for {@link LockSettingsShellCommand}.
+ *
+ * runtest frameworks-services -c com.android.server.LockSettingsShellCommandTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LockSettingsShellCommandTest {
+
+ private LockSettingsShellCommand mCommand;
+
+ private @Mock LockPatternUtils mLockPatternUtils;
+ private int mUserId;
+ private final Binder mBinder = new Binder();
+ private final ShellCallback mShellCallback = new ShellCallback();
+ private final ResultReceiver mResultReceiver = new ResultReceiver(
+ new Handler(Looper.getMainLooper()));
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final Context context = InstrumentationRegistry.getTargetContext();
+ mUserId = ActivityManager.getCurrentUser();
+ mCommand = new LockSettingsShellCommand(context, mLockPatternUtils);
+ }
+
+ @Test
+ public void testWrongPassword() throws Exception {
+ when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+ when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false);
+ assertEquals(-1, mCommand.exec(mBinder, in, out, err,
+ new String[] { "set-pin", "--old", "1234" },
+ mShellCallback, mResultReceiver));
+ verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testChangePin() throws Exception {
+ when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+ when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+ new String[] { "set-pin", "--old", "1234", "4321" },
+ mShellCallback, mResultReceiver));
+ verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC,
+ mUserId);
+ }
+
+ @Test
+ public void testChangePassword() throws Exception {
+ when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+ when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+ new String[] { "set-password", "--old", "1234", "4321" },
+ mShellCallback, mResultReceiver));
+ verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC,
+ mUserId);
+ }
+
+ @Test
+ public void testChangePattern() throws Exception {
+ when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+ when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+ when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true);
+ assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+ new String[] { "set-pattern", "--old", "1234", "4321" },
+ mShellCallback, mResultReceiver));
+ verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId);
+ }
+
+ @Test
+ public void testClear() throws Exception {
+ when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+ when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+ when(mLockPatternUtils.checkPattern(stringToPattern("1234"), mUserId)).thenReturn(true);
+ assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+ new String[] { "clear", "--old", "1234" },
+ mShellCallback, mResultReceiver));
+ verify(mLockPatternUtils).clearLock(mUserId);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 42d9412..3114f3f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -246,7 +246,8 @@
Log.d(TAG, "set mUidObserver to " + mUidObserver);
return null;
}
- }).when(mActivityManager).registerUidObserver(any(), anyInt(), null);
+ }).when(mActivityManager).registerUidObserver(any(), anyInt(),
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
mNetworkManager, mIpm, mTime, mPolicyDir, true);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index bd9e6d1..ba25b16 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -32,7 +31,7 @@
@Override
public void setUp() throws Exception {
super.setUp();
- service = ActivityManagerNative.getDefault();
+ service = ActivityManager.getService();
}
public void testTaskIdsForRunningUsers() throws RemoteException {
@@ -52,4 +51,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
index c9c691d..0359096 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
@@ -22,8 +22,8 @@
import static org.junit.Assert.assertTrue;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
import android.app.Instrumentation.ActivityMonitor;
@@ -63,7 +63,7 @@
@Before
public void setUp() throws Exception {
- mService = ActivityManagerNative.getDefault();
+ mService = ActivityManager.getService();
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 792f300..9f01773 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -737,6 +737,10 @@
// Start the service.
initService();
setCaller(CALLING_PACKAGE_1);
+
+ if (ENABLE_DUMP) {
+ Log.d(TAG, "setUp done");
+ }
}
private static boolean b(Boolean value) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 3cfdc32..771ca146 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4181,7 +4181,7 @@
assertEquals(START_TIME,
findShortcut(shortcuts.getValue(), "s4").getLastChangedTimestamp());
- // Next, send unlock even on user-10. Now we scan packages on this user and send a
+ // Next, send an unlock event on user-10. Now we scan packages on this user and send a
// notification to the launcher.
mInjectedCurrentTimeMillis = START_TIME + 200;
@@ -4222,9 +4222,8 @@
updatePackageVersion(CALLING_PACKAGE_2, 10);
// Then send the broadcast, to only user-0.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
- mService.checkPackageChanges(USER_10);
waitOnMainThread();
@@ -4395,7 +4394,7 @@
});
// Next.
- // Update the build finger print. All system apps will be scanned now.
+ // Update the build finger print. All apps will be scanned now.
mInjectedBuildFingerprint = "update1";
mInjectedCurrentTimeMillis += 1000;
mService.checkPackageChanges(USER_0);
@@ -4406,12 +4405,11 @@
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertWith(getCallerShortcuts())
- .isEmpty();
+ .haveIds("ms1");
});
// Next.
// Update manifest shortcuts.
- mInjectedBuildFingerprint = "update2";
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
@@ -4421,44 +4419,29 @@
mInjectedCurrentTimeMillis += 1000;
mService.checkPackageChanges(USER_0);
- // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
+ // Fingerprint hasn't changed, so there packages weren't scanned.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerShortcuts())
.haveIds("ms1");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertWith(getCallerShortcuts())
- .isEmpty();
+ .haveIds("ms1");
});
- // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
- // still not scanned.
+ // Update the fingerprint. CALLING_PACKAGE_1's version code hasn't changed, but we scan
+ // all apps anyway.
mInjectedBuildFingerprint = "update2";
mInjectedCurrentTimeMillis += 1000;
mService.checkPackageChanges(USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerShortcuts())
- .haveIds("ms1");
- });
- runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- assertWith(getCallerShortcuts())
- .isEmpty();
- });
-
- // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
- mInjectedBuildFingerprint = "update3";
- mInjectedCurrentTimeMillis += 1000;
- updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.checkPackageChanges(USER_0);
-
- runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertWith(getCallerShortcuts())
.haveIds("ms1", "ms2");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertWith(getCallerShortcuts())
- .isEmpty();
+ .haveIds("ms1", "ms2");
});
// Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
@@ -5721,6 +5704,7 @@
R.xml.shortcut_5);
// Unlock user-0.
+ mInjectedCurrentTimeMillis += 100;
mService.handleUnlockUser(USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5750,6 +5734,7 @@
uninstallPackage(USER_10, CALLING_PACKAGE_1);
uninstallPackage(USER_10, CALLING_PACKAGE_3);
+ mInjectedCurrentTimeMillis += 100;
mService.handleUnlockUser(USER_10);
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -5774,6 +5759,8 @@
// hasn't changed.
shutdownServices();
+ mInjectedCurrentTimeMillis += 100;
+
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
@@ -5785,7 +5772,7 @@
mService.handleUnlockUser(USER_0);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+ assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled( // FAIL
mManager.getManifestShortcuts()))),
"ms1");
assertEmpty(mManager.getPinnedShortcuts());
@@ -5808,6 +5795,8 @@
// Do it again, but this time we change the app version, so we do detect the changes.
shutdownServices();
+ mInjectedCurrentTimeMillis += 100;
+
updatePackageVersion(CALLING_PACKAGE_1, 1);
updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1);
@@ -5870,6 +5859,8 @@
shutdownServices();
+ mInjectedCurrentTimeMillis += 100;
+
addManifestShortcutResource(
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index d933cb3..207939f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -33,12 +33,11 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
- * Tests for the {@link WindowState} class.
+ * Tests for the {@link AppWindowToken} class.
*
* Build/Install/Run:
* bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
@@ -46,16 +45,7 @@
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class AppWindowTokenTests {
-
- private static WindowManagerService sWm = null;
- private final IWindow mIWindow = new TestIWindow();
-
- @Before
- public void setUp() throws Exception {
- final Context context = InstrumentationRegistry.getTargetContext();
- sWm = TestWindowManagerPolicy.getWindowManagerService(context);
- }
+public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testAddWindow_Order() throws Exception {
@@ -63,10 +53,11 @@
assertEquals(0, token.getWindowsCount());
- final WindowState win1 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token);
- final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token);
- final WindowState win4 = createWindow(null, TYPE_APPLICATION, token);
+ final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1");
+ final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token,
+ "startingWin");
+ final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
+ final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
token.addWindow(win1);
token.addWindow(startingWin);
@@ -93,24 +84,18 @@
assertNull(token.findMainWindow());
- final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token);
- final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+ final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
+ final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
+ final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
token.addWindow(window1);
assertEquals(window1, token.findMainWindow());
window1.mAnimatingExit = true;
assertEquals(window1, token.findMainWindow());
- final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token);
+ final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
token.addWindow(window2);
assertEquals(window2, token.findMainWindow());
}
- private WindowState createWindow(WindowState parent, int type, WindowToken token) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
- return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0);
- }
-
/* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
private class TestAppWindowToken extends AppWindowToken {
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
new file mode 100644
index 0000000..0801a88
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.ArrayList;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for the {@link DisplayContent} class.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DisplayContentTests extends WindowTestsBase {
+
+ @Test
+ public void testForAllWindows() throws Exception {
+ final DisplayContent dc = new DisplayContent(mDisplay, sWm, null, null);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, dc, "wallpaper");
+ final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, dc, "ime");
+ final WindowState imeDialogWindow = createWindow(null, TYPE_INPUT_METHOD_DIALOG, dc,
+ "ime dialog");
+ final WindowState statusBarWindow = createWindow(null, TYPE_STATUS_BAR, dc, "status bar");
+ final WindowState navBarWindow = createWindow(null, TYPE_NAVIGATION_BAR,
+ statusBarWindow.mToken, "nav bar");
+ final WindowState appWindow = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
+ final WindowState negChildAppWindow = createWindow(appWindow, TYPE_APPLICATION_MEDIA,
+ appWindow.mToken, "negative app child");
+ final WindowState posChildAppWindow = createWindow(appWindow,
+ TYPE_APPLICATION_ATTACHED_DIALOG, appWindow.mToken, "positive app child");
+ final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, dc,
+ "exiting app");
+ final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
+ exitingAppToken.mIsExiting = true;
+ exitingAppToken.mTask.mStack.mExitingAppTokens.add(exitingAppToken);
+
+ final ArrayList<WindowState> windows = new ArrayList();
+
+ // Test forward traversal.
+ dc.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */);
+
+ assertEquals(wallpaperWindow, windows.get(0));
+ assertEquals(exitingAppWindow, windows.get(1));
+ assertEquals(negChildAppWindow, windows.get(2));
+ assertEquals(appWindow, windows.get(3));
+ assertEquals(posChildAppWindow, windows.get(4));
+ assertEquals(statusBarWindow, windows.get(5));
+ assertEquals(navBarWindow, windows.get(6));
+ assertEquals(imeWindow, windows.get(7));
+ assertEquals(imeDialogWindow, windows.get(8));
+
+ // Test backward traversal.
+ windows.clear();
+ dc.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */);
+
+ assertEquals(wallpaperWindow, windows.get(8));
+ assertEquals(exitingAppWindow, windows.get(7));
+ assertEquals(negChildAppWindow, windows.get(6));
+ assertEquals(appWindow, windows.get(5));
+ assertEquals(posChildAppWindow, windows.get(4));
+ assertEquals(statusBarWindow, windows.get(3));
+ assertEquals(navBarWindow, windows.get(2));
+ assertEquals(imeWindow, windows.get(1));
+ assertEquals(imeDialogWindow, windows.get(0));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 38a98b2..ed4c79f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -272,22 +272,26 @@
}
@Override
- public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) {
+ public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
return 0;
}
@Override
- public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) {
+ public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
return 0;
}
@Override
- public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) {
+ public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
return 0;
}
@Override
- public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) {
+ public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ int displayId) {
return 0;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
new file mode 100644
index 0000000..5a035d6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
+/**
+ * Tests for the {@link WindowLayersController} class.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowLayersControllerTests extends WindowTestsBase {
+
+ private static boolean sOneTimeSetupDone = false;
+ private static WindowLayersController sLayersController;
+ private static DisplayContent sDisplayContent;
+ private static WindowState sImeWindow;
+ private static WindowState sImeDialogWindow;
+ private static WindowState sStatusBarWindow;
+ private static WindowState sDockedDividerWindow;
+ private static WindowState sNavBarWindow;
+ private static WindowState sAppWindow;
+ private static WindowState sChildAppWindow;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ if (sOneTimeSetupDone) {
+ return;
+ }
+ sOneTimeSetupDone = true;
+ sLayersController = new WindowLayersController(sWm);
+ sDisplayContent =
+ new DisplayContent(mDisplay, sWm, sLayersController, new WallpaperController(sWm));
+ final WindowState wallpaperWindow =
+ createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
+ sImeWindow = createWindow(null, TYPE_INPUT_METHOD, sDisplayContent, "sImeWindow");
+ sImeDialogWindow =
+ createWindow(null, TYPE_INPUT_METHOD_DIALOG, sDisplayContent, "sImeDialogWindow");
+ sStatusBarWindow = createWindow(null, TYPE_STATUS_BAR, sDisplayContent, "sStatusBarWindow");
+ sNavBarWindow =
+ createWindow(null, TYPE_NAVIGATION_BAR, sStatusBarWindow.mToken, "sNavBarWindow");
+ sDockedDividerWindow =
+ createWindow(null, TYPE_DOCK_DIVIDER, sDisplayContent, "sDockedDividerWindow");
+ sAppWindow = createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "sAppWindow");
+ sChildAppWindow = createWindow(sAppWindow,
+ TYPE_APPLICATION_ATTACHED_DIALOG, sAppWindow.mToken, "sChildAppWindow");
+ }
+
+ @Test
+ public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+ sWm.mInputMethodTarget = null;
+ sLayersController.assignWindowLayers(sDisplayContent);
+
+ // The Ime has an higher base layer than app windows and lower base layer than system
+ // windows, so it should be above app windows and below system windows if there isn't an IME
+ // target.
+ assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+ assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+ assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+ // And, IME dialogs should always have an higher layer than the IME.
+ assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+ }
+
+ @Test
+ public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+ final WindowState imeAppTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget");
+ sWm.mInputMethodTarget = imeAppTarget;
+ sLayersController.assignWindowLayers(sDisplayContent);
+
+ // Ime should be above all app windows and below system windows if it is targeting an app
+ // window.
+ assertWindowLayerGreaterThan(sImeWindow, imeAppTarget);
+ assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+ assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+ assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow);
+
+ // And, IME dialogs should always have an higher layer than the IME.
+ assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+ }
+
+ @Test
+ public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+ final WindowState imeSystemOverlayTarget =
+ createWindow(null, TYPE_SYSTEM_OVERLAY, sDisplayContent, "imeSystemOverlayTarget");
+
+ sWm.mInputMethodTarget = imeSystemOverlayTarget;
+ sLayersController.assignWindowLayers(sDisplayContent);
+
+ // The IME target base layer is higher than all window except for the nav bar window, so the
+ // IME should be above all windows except for the nav bar.
+ assertWindowLayerGreaterThan(sImeWindow, imeSystemOverlayTarget);
+ assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sAppWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow);
+ assertWindowLayerGreaterThan(sImeWindow, sStatusBarWindow);
+ assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow);
+
+ // And, IME dialogs should always have an higher layer than the IME.
+ assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow);
+ }
+
+ private void assertWindowLayerGreaterThan(WindowState first, WindowState second)
+ throws Exception {
+ assertGreaterThan(first.mWinAnimator.mAnimLayer, second.mWinAnimator.mAnimLayer);
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 3df1df9..50e5a22 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -41,32 +41,30 @@
/**
* Tests for the {@link WindowState} class.
*
- * Build: mmma -j32 frameworks/base/services/tests/servicestests
- * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
- * Run: adb shell am instrument -w -e class com.android.server.wm.WindowStateTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * runtest frameworks-services -c com.android.server.wm.WindowStateTests
*/
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class WindowStateTests {
+public class WindowStateTests extends WindowTestsBase {
- private static WindowManagerService sWm = null;
private WindowToken mWindowToken;
- private final IWindow mIWindow = new TestIWindow();
@Before
public void setUp() throws Exception {
- final Context context = InstrumentationRegistry.getTargetContext();
- sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+ super.setUp();
mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
sWm.getDefaultDisplayContentLocked());
}
@Test
public void testIsParentWindowHidden() throws Exception {
- final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
- final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
- final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
+ final WindowState parentWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+ final WindowState child1 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+ final WindowState child2 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
assertFalse(parentWindow.mHidden);
assertFalse(parentWindow.isParentWindowHidden());
@@ -81,10 +79,14 @@
@Test
public void testIsChildWindow() throws Exception {
- final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
- final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
- final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
- final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
+ final WindowState parentWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+ final WindowState child1 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+ final WindowState child2 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
+ final WindowState randomWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
assertFalse(parentWindow.isChildWindow());
assertTrue(child1.isChildWindow());
@@ -94,12 +96,13 @@
@Test
public void testHasChild() throws Exception {
- final WindowState win1 = createWindow(null, TYPE_APPLICATION);
- final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW);
- final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW);
- final WindowState win2 = createWindow(null, TYPE_APPLICATION);
- final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW);
- final WindowState randomWindow = createWindow(null, TYPE_APPLICATION);
+ final WindowState win1 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win1");
+ final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win11");
+ final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, mWindowToken, "win12");
+ final WindowState win2 = createWindow(null, TYPE_APPLICATION, mWindowToken, "win2");
+ final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW, mWindowToken, "win21");
+ final WindowState randomWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "randomWindow");
assertTrue(win1.hasChild(win11));
assertTrue(win1.hasChild(win12));
@@ -115,23 +118,28 @@
@Test
public void testGetBottomChild() throws Exception {
- final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
+ final WindowState parentWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
assertNull(parentWindow.getBottomChild());
- final WindowState child1 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
+ final WindowState child1 =
+ createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child1");
assertEquals(child1, parentWindow.getBottomChild());
- final WindowState child2 = createWindow(parentWindow, TYPE_APPLICATION_PANEL);
+ final WindowState child2 =
+ createWindow(parentWindow, TYPE_APPLICATION_PANEL, mWindowToken, "child2");
// Since child1 and child2 are at the same layer, then child2 is expect to be added on top
// on child1
assertEquals(child1, parentWindow.getBottomChild());
- final WindowState child3 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
+ final WindowState child3 =
+ createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child3");
// Since child3 is a negative layer, we would expect it to be added below current children
// with positive layers.
assertEquals(child3, parentWindow.getBottomChild());
- final WindowState child4 = createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY);
+ final WindowState child4 =
+ createWindow(parentWindow, TYPE_APPLICATION_MEDIA_OVERLAY, mWindowToken, "child4");
// We would also expect additional negative layers to be added below existing negative
// layers.
assertEquals(child4, parentWindow.getBottomChild());
@@ -139,9 +147,12 @@
@Test
public void testGetParentWindow() throws Exception {
- final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
- final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
- final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW);
+ final WindowState parentWindow =
+ createWindow(null, TYPE_APPLICATION, mWindowToken, "parentWindow");
+ final WindowState child1 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child1");
+ final WindowState child2 =
+ createWindow(parentWindow, FIRST_SUB_WINDOW, mWindowToken, "child2");
assertNull(parentWindow.getParentWindow());
assertEquals(parentWindow, child1.getParentWindow());
@@ -150,9 +161,9 @@
@Test
public void testGetTopParentWindow() throws Exception {
- final WindowState root = createWindow(null, TYPE_APPLICATION);
- final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW);
- final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW);
+ final WindowState root = createWindow(null, TYPE_APPLICATION, mWindowToken, "root");
+ final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, mWindowToken, "child1");
+ final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, mWindowToken, "child2");
assertEquals(root, root.getTopParentWindow());
assertEquals(root, child1.getTopParentWindow());
@@ -160,9 +171,12 @@
assertEquals(root, child2.getTopParentWindow());
}
- private WindowState createWindow(WindowState parent, int type) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
- return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0, 0);
+ @Test
+ public void testIsOnScreen_hiddenByPolicy() {
+ final WindowState window = createWindow(null, TYPE_APPLICATION, mWindowToken, "window");
+ window.setHasSurface(true);
+ assertTrue(window.isOnScreen());
+ window.hideLw(false /* doAnimation */);
+ assertFalse(window.isOnScreen());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
new file mode 100644
index 0000000..9681bd2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import org.junit.Assert;
+import org.junit.Before;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.support.test.InstrumentationRegistry;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.res.Configuration.EMPTY;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Common base class for window manager unit test classes.
+ */
+public class WindowTestsBase {
+ static WindowManagerService sWm = null;
+ private final IWindow mIWindow = new TestIWindow();
+ private final Session mMockSession = mock(Session.class);
+ Display mDisplay;
+ private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
+ private static int sNextTaskId = 0;
+
+ @Before
+ public void setUp() throws Exception {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+ mDisplay = context.getDisplay();
+ }
+
+ /** Asserts that the first entry is greater than the second entry. */
+ void assertGreaterThan(int first, int second) throws Exception {
+ Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
+ }
+
+ WindowToken createWindowToken(DisplayContent dc, int type) {
+ if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
+ return new WindowToken(sWm, mock(IBinder.class), type, false, dc);
+ }
+
+ final int stackId = sNextStackId++;
+ dc.addStackToDisplay(stackId, true);
+ final TaskStack stack = sWm.mStackIdToStack.get(stackId);
+ final Task task = new Task(sNextTaskId++, stack, 0, sWm, null, EMPTY, false);
+ stack.addTask(task, true);
+ final AppWindowToken token = new AppWindowToken(sWm, null, false, dc);
+ task.addAppToken(0, token, 0, false);
+ return token;
+ }
+
+ WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
+ final WindowToken token = createWindowToken(dc, type);
+ return createWindow(parent, type, token, name);
+ }
+
+ WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+ attrs.setTitle(name);
+
+ final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
+ 0, attrs, 0, 0);
+ // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
+ // adding it to the token...
+ token.addWindow(w);
+ return w;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 5326a19..d6bfa17 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -39,7 +39,7 @@
import static org.mockito.Mockito.mock;
/**
- * Tests for the {@link WindowState} class.
+ * Tests for the {@link WindowToken} class.
*
* Build/Install/Run:
* bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
@@ -47,17 +47,7 @@
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class WindowTokenTests {
-
- private WindowManagerService mWm = null;
- private final IWindow mIWindow = new TestIWindow();
- private final Session mMockSession = mock(Session.class);
-
- @Before
- public void setUp() throws Exception {
- final Context context = InstrumentationRegistry.getTargetContext();
- mWm = TestWindowManagerPolicy.getWindowManagerService(context);
- }
+public class WindowTokenTests extends WindowTestsBase {
@Test
public void testAddWindow() throws Exception {
@@ -65,11 +55,11 @@
assertEquals(0, token.getWindowsCount());
- final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+ final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
+ final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
+ final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
+ final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
+ final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
token.addWindow(window1);
// NOTE: Child windows will not be added to the token as window containers can only
@@ -91,12 +81,12 @@
@Test
public void testChildRemoval() throws Exception {
final TestWindowToken token = new TestWindowToken();
- final DisplayContent dc = mWm.getDefaultDisplayContentLocked();
+ final DisplayContent dc = sWm.getDefaultDisplayContentLocked();
assertEquals(token, dc.getWindowToken(token.token));
- final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+ final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
+ final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
token.addWindow(window1);
token.addWindow(window2);
@@ -113,11 +103,11 @@
@Test
public void testAdjustAnimLayer() throws Exception {
final TestWindowToken token = new TestWindowToken();
- final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
- final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+ final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
+ final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
+ final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
+ final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
+ final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
token.addWindow(window1);
token.addWindow(window2);
@@ -136,60 +126,11 @@
assertEquals(window3StartLayer + adj, highestLayer);
}
- @Test
- public void testGetTopWindow() throws Exception {
- final TestWindowToken token = new TestWindowToken();
-
- assertNull(token.getTopWindow());
-
- final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
- token.addWindow(window1);
- assertEquals(window1, token.getTopWindow());
- final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
- assertEquals(window12, token.getTopWindow());
-
- final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
- token.addWindow(window2);
- // Since new windows are added to the bottom of the token, we would still expect the
- // previous one to the top.
- assertEquals(window12, token.getTopWindow());
- }
-
- @Test
- public void testGetWindowIndex() throws Exception {
- final TestWindowToken token = new TestWindowToken();
-
- final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
- assertEquals(-1, token.getWindowIndex(window1));
- token.addWindow(window1);
- assertEquals(0, token.getWindowIndex(window1));
- final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
- final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
- // Child windows should report the same index as their parents.
- assertEquals(0, token.getWindowIndex(window11));
- assertEquals(0, token.getWindowIndex(window12));
-
- final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
- assertEquals(-1, token.getWindowIndex(window2));
- token.addWindow(window2);
- // Since new windows are added to the bottom of the token, we would expect the added window
- // to be at index 0.
- assertEquals(0, token.getWindowIndex(window2));
- assertEquals(1, token.getWindowIndex(window1));
- }
-
- private WindowState createWindow(WindowState parent, int type, WindowToken token) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
-
- return new WindowState(mWm, mMockSession, mIWindow, token, parent, OP_NONE, 0, attrs, 0, 0);
- }
-
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
private class TestWindowToken extends WindowToken {
TestWindowToken() {
- super(mWm, mock(IBinder.class), 0, false, mWm.getDefaultDisplayContentLocked());
+ super(sWm, mock(IBinder.class), 0, false, sWm.getDefaultDisplayContentLocked());
}
int getWindowsCount() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 04104b5..7217c3b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -17,7 +17,7 @@
package com.android.server.usage;
import android.Manifest;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
@@ -462,7 +462,7 @@
final int[] runningUserIds;
try {
- runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ runningUserIds = ActivityManager.getService().getRunningUserIds();
if (checkUserId != UserHandle.USER_ALL
&& !ArrayUtils.contains(runningUserIds, checkUserId)) {
return false;
@@ -1311,7 +1311,7 @@
@Override
public boolean isAppInactive(String packageName, int userId) {
try {
- userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
+ userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1329,7 +1329,7 @@
public void setAppInactive(String packageName, boolean idle, int userId) {
final int callingUid = Binder.getCallingUid();
try {
- userId = ActivityManagerNative.getDefault().handleIncomingUser(
+ userId = ActivityManager.getService().handleIncomingUser(
Binder.getCallingPid(), callingUid, userId, false, true,
"setAppIdle", null);
} catch (RemoteException re) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index a46ccee..4357dca 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -117,7 +116,7 @@
mServiceStub = stub;
mUser = userHandle;
mComponent = service;
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
VoiceInteractionServiceInfo info;
try {
info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 7dacf16..4267ec4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -17,7 +17,6 @@
package com.android.server.voiceinteraction;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.assist.AssistContent;
@@ -182,7 +181,7 @@
mCallback = callback;
mCallingUid = callingUid;
mHandler = handler;
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mAppOps = context.getSystemService(AppOpsManager.class);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 62625bd..c99e22a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -843,6 +843,7 @@
private String mParentId = null;
private int mState;
private List<String> mCannedTextResponses = null;
+ private String mCallingPackage;
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
private Details mDetails;
@@ -1330,19 +1331,22 @@
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = STATE_NEW;
+ mCallingPackage = callingPackage;
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
+ String callingPackage) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = state;
+ mCallingPackage = callingPackage;
}
/** {@hide} */
@@ -1352,6 +1356,7 @@
/** {@hide} */
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
+
// First, we update the internal state as far as possible before firing any updates.
Details details = Details.createFromParcelableCall(parcelableCall);
boolean detailsChanged = !Objects.equals(mDetails, details);
@@ -1367,7 +1372,7 @@
cannedTextResponsesChanged = true;
}
- VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
+ VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
!Objects.equals(mVideoCallImpl, newVideoCallImpl);
if (videoCallChanged) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8f9c758..2b9a508 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -785,7 +786,7 @@
public static final int SESSION_EVENT_TX_STOP = 4;
/**
- * A camera failure has occurred for the selected camera. The {@link InCallService} can use
+ * A camera failure has occurred for the selected camera. The {@link VideoProvider} can use
* this as a cue to inform the user the camera is not available.
* @see #handleCallSessionEvent(int)
*/
@@ -793,13 +794,21 @@
/**
* Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
- * for operation. The {@link InCallService} can use this as a cue to inform the user that
+ * for operation. The {@link VideoProvider} can use this as a cue to inform the user that
* the camera has become available again.
* @see #handleCallSessionEvent(int)
*/
public static final int SESSION_EVENT_CAMERA_READY = 6;
/**
+ * Session event raised by Telecom when
+ * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
+ * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
+ * @see #handleCallSessionEvent(int)
+ */
+ public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
+
+ /**
* Session modify request was successful.
* @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
*/
@@ -848,6 +857,8 @@
private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+ private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
+ "CAMERA_PERMISSION_ERROR";
private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
private VideoProvider.VideoProviderHandler mMessageHandler;
@@ -906,8 +917,17 @@
break;
}
case MSG_SET_CAMERA:
- onSetCamera((String) msg.obj);
- break;
+ {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ onSetCamera((String) args.arg1);
+ onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
+ args.argi2);
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
case MSG_SET_PREVIEW_SURFACE:
onSetPreviewSurface((Surface) msg.obj);
break;
@@ -962,8 +982,19 @@
MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
}
- public void setCamera(String cameraId) {
- mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
+ public void setCamera(String cameraId, String callingPackageName) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = cameraId;
+ // Propagate the calling package; originally determined in
+ // android.telecom.InCallService.VideoCall#setCamera(String) from the calling
+ // process.
+ args.arg2 = callingPackageName;
+ // Pass along the uid and pid of the calling app; this gets lost when we put the
+ // message onto the handler. These are required for Telecom to perform a permission
+ // check to see if the calling app is able to use the camera.
+ args.argi1 = Binder.getCallingUid();
+ args.argi2 = Binder.getCallingPid();
+ mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
}
public void setPreviewSurface(Surface surface) {
@@ -1048,6 +1079,29 @@
public abstract void onSetCamera(String cameraId);
/**
+ * Sets the camera to be used for the outgoing video.
+ * <p>
+ * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
+ * camera via
+ * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
+ * <p>
+ * This prototype is used internally to ensure that the calling package name, UID and PID
+ * are sent to Telecom so that can perform a camera permission check on the caller.
+ * <p>
+ * Sent from the {@link InCallService} via
+ * {@link InCallService.VideoCall#setCamera(String)}.
+ *
+ * @param cameraId The id of the camera (use ids as reported by
+ * {@link CameraManager#getCameraIdList()}).
+ * @param callingPackageName The AppOpps package name of the caller.
+ * @param callingUid The UID of the caller.
+ * @param callingPid The PID of the caller.
+ * @hide
+ */
+ public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
+ int callingPid) {}
+
+ /**
* Sets the surface to be used for displaying a preview of what the user's camera is
* currently capturing. When video transmission is enabled, this is the video signal which
* is sent to the remote device.
@@ -1233,7 +1287,8 @@
* {@link VideoProvider#SESSION_EVENT_TX_START},
* {@link VideoProvider#SESSION_EVENT_TX_STOP},
* {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
- * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
+ * {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
+ * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
*/
public void handleCallSessionEvent(int event) {
if (mVideoCallbacks != null) {
@@ -1382,6 +1437,8 @@
return SESSION_EVENT_TX_START_STR;
case SESSION_EVENT_TX_STOP:
return SESSION_EVENT_TX_STOP_STR;
+ case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
+ return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
default:
return SESSION_EVENT_UNKNOWN_STR + " " + event;
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 69de89d..5d68aae 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -87,7 +87,8 @@
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
- mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+ String callingPackage = getApplicationContext().getOpPackageName();
+ mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
mPhone.addListener(mPhoneListener);
onPhoneCreated(mPhone);
break;
@@ -664,7 +665,8 @@
* {@link Connection.VideoProvider#SESSION_EVENT_TX_START},
* {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP},
* {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
- * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}.
+ * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY},
+ * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}.
*/
public abstract void onCallSessionEvent(int event);
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 4a6fd7c..1900cb9 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -182,10 +182,10 @@
* @return The video call.
*/
- public VideoCallImpl getVideoCallImpl() {
+ public VideoCallImpl getVideoCallImpl(String callingPackageName) {
if (mVideoCall == null && mVideoCallProvider != null) {
try {
- mVideoCall = new VideoCallImpl(mVideoCallProvider);
+ mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
} catch (RemoteException ignored) {
// Ignore RemoteException.
}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a4ef560..30ec5b3 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,13 +125,16 @@
private boolean mCanAddCall = true;
- Phone(InCallAdapter adapter) {
+ private final String mCallingPackage;
+
+ Phone(InCallAdapter adapter, String callingPackage) {
mInCallAdapter = adapter;
+ mCallingPackage = callingPackage;
}
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
- parcelableCall.getState());
+ parcelableCall.getState(), mCallingPackage);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 473e394..0457d63 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -114,7 +114,10 @@
public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
/**
- * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
+ * Flag indicating that this {@code PhoneAccount} is currently able to place video calls.
+ * <p>
+ * See also {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING} which indicates whether the
+ * {@code PhoneAccount} supports placing video calls.
* <p>
* See {@link #getCapabilities}
*/
@@ -179,6 +182,23 @@
public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
/**
+ * Flag indicating that this {@link PhoneAccount} supports video calling.
+ * This is not an indication that the {@link PhoneAccount} is currently able to make a video
+ * call, but rather that it has the ability to make video calls (but not necessarily at this
+ * time).
+ * <p>
+ * Whether a {@link PhoneAccount} can make a video call is ultimately controlled by
+ * {@link #CAPABILITY_VIDEO_CALLING}, which indicates whether the {@link PhoneAccount} is
+ * currently capable of making a video call. Consider a case where, for example, a
+ * {@link PhoneAccount} supports making video calls (e.g.
+ * {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING}), but a current lack of network connectivity
+ * prevents video calls from being made (e.g. {@link #CAPABILITY_VIDEO_CALLING}).
+ * <p>
+ * See {@link #getCapabilities}
+ */
+ public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400;
+
+ /**
* URI scheme for telephone number URIs.
*/
public static final String SCHEME_TEL = "tel";
@@ -762,6 +782,9 @@
*/
private String capabilitiesToString(int capabilities) {
StringBuilder sb = new StringBuilder();
+ if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) {
+ sb.append("SuppVideo ");
+ }
if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) {
sb.append("Video ");
}
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 0e4f53e..77e0e54 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -408,6 +408,8 @@
private final IVideoProvider mVideoProviderBinder;
+ private final String mCallingPackage;
+
/**
* ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
* load factor before resizing, 1 means we only expect a single thread to
@@ -416,8 +418,9 @@
private final Set<Callback> mCallbacks = Collections.newSetFromMap(
new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
- VideoProvider(IVideoProvider videoProviderBinder) {
+ VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
mVideoProviderBinder = videoProviderBinder;
+ mCallingPackage = callingPackage;
try {
mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
} catch (RemoteException e) {
@@ -452,7 +455,7 @@
*/
public void setCamera(String cameraId) {
try {
- mVideoProviderBinder.setCamera(cameraId);
+ mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
} catch (RemoteException e) {
}
}
@@ -628,7 +631,7 @@
* @hide
*/
RemoteConnection(String callId, IConnectionService connectionService,
- ParcelableConnection connection) {
+ ParcelableConnection connection, String callingPackage) {
mConnectionId = callId;
mConnectionService = connectionService;
mConnected = true;
@@ -640,7 +643,7 @@
mVideoState = connection.getVideoState();
IVideoProvider videoProvider = connection.getVideoProvider();
if (videoProvider != null) {
- mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+ mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
} else {
mVideoProvider = null;
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 0a8470a..d8a226a 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -283,9 +283,13 @@
@Override
public void setVideoProvider(String callId, IVideoProvider videoProvider,
Session.Info sessionInfo) {
+
+ String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
+ .getOpPackageName();
RemoteConnection.VideoProvider remoteVideoProvider = null;
if (videoProvider != null) {
- remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+ remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
+ callingPackage);
}
findConnectionForAction(callId, "setVideoProvider")
.setVideoProvider(remoteVideoProvider);
@@ -351,8 +355,10 @@
@Override
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
+ String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
+ getOpPackageName();
RemoteConnection remoteConnection = new RemoteConnection(callId,
- mOutgoingConnectionServiceRpc, connection);
+ mOutgoingConnectionServiceRpc, connection, callingPackage);
mConnectionById.put(callId, remoteConnection);
remoteConnection.registerCallback(new RemoteConnection.Callback() {
@Override
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index e54abee..d8ede5c 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -43,6 +43,7 @@
private VideoCall.Callback mCallback;
private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+ private final String mCallingPackageName;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -197,12 +198,13 @@
private Handler mHandler;
- VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
+ VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
mVideoProvider = videoProvider;
mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
mBinder = new VideoCallListenerBinder();
mVideoProvider.addVideoCallback(mBinder);
+ mCallingPackageName = callingPackageName;
}
public void destroy() {
@@ -240,7 +242,8 @@
/** {@inheritDoc} */
public void setCamera(String cameraId) {
try {
- mVideoProvider.setCamera(cameraId);
+ Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
+ mVideoProvider.setCamera(cameraId, mCallingPackageName);
} catch (RemoteException e) {
}
}
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index 68e5fd4..a109e90 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@
void removeVideoCallback(IBinder videoCallbackBinder);
- void setCamera(String cameraId);
+ void setCamera(String cameraId, in String mCallingPackageName);
void setPreviewSurface(in Surface surface);
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 3c0a8d6..434caad 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -168,20 +168,34 @@
}
/**
- * @hide
+ * Get reference signal received quality
*/
public int getRsrq() {
return mRsrq;
}
/**
- * @hide
+ * Get reference signal signal-to-noise ratio
*/
public int getRssnr() {
return mRssnr;
}
/**
+ * Get reference signal received power
+ */
+ public int getRsrp() {
+ return mRsrp;
+ }
+
+ /**
+ * Get channel quality indicator
+ */
+ public int getCqi() {
+ return mCqi;
+ }
+
+ /**
* Get signal strength as dBm
*/
@Override
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index bb2b447..32f487b 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -233,7 +233,7 @@
* @hide
*/
/** @hide */
- protected int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ protected Integer mSubId;
private final Handler mHandler;
@@ -242,7 +242,7 @@
* This class requires Looper.myLooper() not return null.
*/
public PhoneStateListener() {
- this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, Looper.myLooper());
+ this(null, Looper.myLooper());
}
/**
@@ -251,7 +251,7 @@
* @hide
*/
public PhoneStateListener(Looper looper) {
- this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, looper);
+ this(null, looper);
}
/**
@@ -260,7 +260,7 @@
* own non-null Looper use PhoneStateListener(int subId, Looper looper) below.
* @hide
*/
- public PhoneStateListener(int subId) {
+ public PhoneStateListener(Integer subId) {
this(subId, Looper.myLooper());
}
@@ -269,7 +269,7 @@
* and non-null Looper.
* @hide
*/
- public PhoneStateListener(int subId, Looper looper) {
+ public PhoneStateListener(Integer subId, Looper looper) {
if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
mSubId = subId;
mHandler = new Handler(looper) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index dcf2f06..20dd012 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -263,6 +263,22 @@
return new TelephonyManager(mContext, subId);
}
+ /**
+ * Create a new TelephonyManager object pinned to the subscription ID associated with the given
+ * phone account.
+ *
+ * @return a TelephonyManager that uses the given phone account for all calls, or {@code null}
+ * if the phone account does not correspond to a valid subscription ID.
+ */
+ @Nullable
+ public TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+ int subId = getSubIdForPhoneAccountHandle(phoneAccountHandle);
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ return null;
+ }
+ return new TelephonyManager(mContext, subId);
+ }
+
/** {@hide} */
public boolean isMultiSimEnabled() {
return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
@@ -3019,6 +3035,12 @@
if (mContext == null) return;
try {
Boolean notifyNow = (getITelephony() != null);
+ // If the listener has not explicitly set the subId (for example, created with the
+ // default constructor), replace the subId so it will listen to the account the
+ // telephony manager is created with.
+ if (listener.mSubId == null) {
+ listener.mSubId = mSubId;
+ }
sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
} catch (RemoteException ex) {
@@ -5446,6 +5468,19 @@
return retval;
}
+ private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+ int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ try {
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ retval = getSubIdForPhoneAccount(service.getPhoneAccount(phoneAccountHandle));
+ }
+ } catch (RemoteException e) {
+ }
+
+ return retval;
+ }
+
/**
* Resets telephony manager settings back to factory defaults.
*
@@ -5495,6 +5530,16 @@
}
/**
+ * Returns the current {@link ServiceState} information.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ public ServiceState getServiceState() {
+ return getServiceStateForSubscriber(getSubId());
+ }
+
+ /**
* Returns the service state information on specified subscription. Callers require
* either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
* @hide
diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
index 5b71149..2ae424f 100644
--- a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
+++ b/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
@@ -89,4 +89,11 @@
*/
void listCapInfoReceived(in PresRlmiInfo rlmiInfo,
in PresResInfo [] resInfo);
+
+ /**
+ * Callback function to be invoked to inform the client when Unpublish message
+ * is sent to network.
+ */
+ void unpublishMessageSent();
+
}
\ No newline at end of file
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 5ef71df..e443911 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -147,6 +147,12 @@
public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
return MockContentProvider.this.uncanonicalize(uri);
}
+
+ @Override
+ public boolean refresh(String callingPkg, Uri url, Bundle args,
+ ICancellationSignal cancellationSignal) throws RemoteException {
+ return MockContentProvider.this.refresh(url, args);
+ }
}
private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
@@ -251,6 +257,13 @@
}
/**
+ * @hide
+ */
+ public boolean refresh(Uri url, Bundle args) {
+ throw new UnsupportedOperationException("unimplemented mock method call");
+ }
+
+ /**
* Returns IContentProvider which calls back same methods in this class.
* By overriding this class, we avoid the mechanism hidden behind ContentProvider
* (IPC, etc.)
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index fdd971b..190fc35 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -17,6 +17,8 @@
package android.test.mock;
import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -759,4 +761,23 @@
public boolean isCredentialProtectedStorage() {
throw new UnsupportedOperationException();
}
+
+ /** {@hide} */
+ @Override
+ public IBinder getActivityToken() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index ee8c376..09d45d1 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -125,4 +125,10 @@
public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+
+ @Override
+ public boolean refresh(String callingPkg, Uri url, Bundle args,
+ ICancellationSignal cancellationSignal) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
}
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index f5f7ea3..0aa20ef 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -19,7 +19,6 @@
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.app.ActivityManagerNative;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
@@ -144,7 +143,7 @@
InstrumentationTestRunner instrumentation =
(InstrumentationTestRunner)getInstrumentation();
Bundle args = instrumentation.getArguments();
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
index b659135..7a4fddf 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
@@ -17,7 +17,6 @@
package com.android.imftest.samples;
import android.app.Activity;
-import android.app.ActivityManagerNative;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.MediaStore;
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index a7e3bec..1ae318a 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.UiAutomation;
import android.content.Context;
@@ -84,7 +83,7 @@
MemoryUsageInstrumentation instrumentation =
(MemoryUsageInstrumentation) getInstrumentation();
Bundle args = instrumentation.getBundle();
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
createMappings();
parseArgs(args);
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 6ff0c5a..6a064d2 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -25,7 +25,7 @@
import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
import static com.android.server.connectivity.MetricsTestUtil.b;
import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index c7982b1..78d16d9 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -34,7 +34,7 @@
import android.os.Parcelable;
import android.util.Base64;
-import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
import junit.framework.TestCase;
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index a30b362..9f7261d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -59,13 +59,14 @@
@Mock private INetworkStatsService mStatsService;
@Mock private IControlsTethering mTetherHelper;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
+ @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
private final TestLooper mLooper = new TestLooper();
private TetherInterfaceStateMachine mTestedSm;
private void initStateMachine(int interfaceType) throws Exception {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
- mNMService, mStatsService, mTetherHelper);
+ mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
// the test of the world that we've changed from an unknown to available state.
@@ -91,7 +92,8 @@
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper);
+ ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
verify(mTetherHelper).notifyInterfaceStateChange(
@@ -274,4 +276,4 @@
upstreamIface);
mLooper.dispatchAll();
}
-}
\ No newline at end of file
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index d7f4a38..89bd8d8 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -16,7 +16,7 @@
package com.android.framework.permission.tests;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.res.Configuration;
import android.os.RemoteException;
@@ -33,7 +33,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mAm = ActivityManagerNative.getDefault();
+ mAm = ActivityManager.getService();
}
@SmallTest
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 8dd176d..a3404e5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
static const char* sMajorVersion = "2";
// Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "2";
+static const char* sMinorVersion = "3";
int PrintVersion() {
std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 1d414743..3eef7aa7 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -41,6 +41,8 @@
return "dimen";
case ResourceType::kDrawable:
return "drawable";
+ case ResourceType::kFont:
+ return "font";
case ResourceType::kFraction:
return "fraction";
case ResourceType::kId:
@@ -83,6 +85,7 @@
{"color", ResourceType::kColor},
{"dimen", ResourceType::kDimen},
{"drawable", ResourceType::kDrawable},
+ {"font", ResourceType::kFont},
{"fraction", ResourceType::kFraction},
{"id", ResourceType::kId},
{"integer", ResourceType::kInteger},
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 78acb70..13330b5 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -46,6 +46,7 @@
kColor,
kDimen,
kDrawable,
+ kFont,
kFraction,
kId,
kInteger,
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 720ab91..6acb4d3 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -57,6 +57,10 @@
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kDrawable);
+ type = ParseResourceType("font");
+ ASSERT_NE(type, nullptr);
+ EXPECT_EQ(*type, ResourceType::kFont);
+
type = ParseResourceType("fraction");
ASSERT_NE(type, nullptr);
EXPECT_EQ(*type, ResourceType::kFraction);
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index a06140c..f0b18e6 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -482,7 +482,9 @@
void BackUp(int count) override { buffer_->BackUp(count); }
- int64_t ByteCount() const override { return buffer_->size(); }
+ google::protobuf::int64 ByteCount() const override {
+ return buffer_->size();
+ }
bool HadError() const override { return false; }
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index f1bc53e..7ab05b5 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -232,6 +232,13 @@
}
}*/
+#ifdef MAX
+#undef MAX
+#endif
+#ifdef ABS
+#undef ABS
+#endif
+
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(a) ((a) < 0 ? -(a) : (a))
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index 01c9adb..aff1da3 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -62,8 +62,8 @@
void BackUp(int count) override;
bool Skip(int count) override;
- int64_t ByteCount() const override {
- return static_cast<int64_t>(window_start_);
+ google::protobuf::int64 ByteCount() const override {
+ return static_cast<google::protobuf::int64>(window_start_);
}
bool HadError() const override { return error_; }
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml
new file mode 100644
index 0000000..1fb6791
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/myfont-normal" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/myfont-italic" />
+</font-family>
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 68db6b3..0d0e46d 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -361,7 +361,7 @@
bool CompiledFileInputStream::ReadCompiledFile(pb::CompiledFile* out_val) {
EnsureAlignedRead();
- uint64_t pb_size = 0u;
+ google::protobuf::uint64 pb_size = 0u;
if (!in_.ReadLittleEndian64(&pb_size)) {
return false;
}
@@ -389,7 +389,7 @@
uint64_t* out_len) {
EnsureAlignedRead();
- uint64_t pb_size = 0u;
+ google::protobuf::uint64 pb_size = 0u;
if (!in_.ReadLittleEndian64(&pb_size)) {
return false;
}
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 93c790d..ac411b15 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,9 @@
# Android Asset Packaging Tool 2.0 (AAPT2) release notes
+## Version 2.3
+### `aapt2`
+- Support new `font` resource type.
+
## Version 2.2
### `aapt2 compile ...`
- Added support for inline complex XML resources. See
diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore
index eb52b64..819103d 100644
--- a/tools/layoutlib/.gitignore
+++ b/tools/layoutlib/.gitignore
@@ -1,3 +1,4 @@
bin
/.idea/workspace.xml
/out
+/bridge/out
diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml
index 57d08cb..fbaed52 100644
--- a/tools/layoutlib/bridge/bridge.iml
+++ b/tools/layoutlib/bridge/bridge.iml
@@ -7,6 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/tests/src" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/src/main/myapplication.widgets" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.settings" />
<excludeFolder url="file://$MODULE_DIR$/bin" />
<excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/.gradle" />
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index e1fc5ec..2ae4654 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -326,7 +326,7 @@
@LayoutlibDelegate
/*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize, boolean isPremultiplied) {
+ int config, boolean isPremultiplied) {
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
"Bitmap.reconfigure() is not supported", null /*data*/);
}
@@ -600,6 +600,22 @@
return Arrays.equals(argb1, argb2);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetAllocationByteCount(long nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+ return nativeRowBytes(nativeBitmap) * delegate.mImage.getHeight();
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativePrepareToDraw(long nativeBitmap) {
+ // do nothing as Bitmap_Delegate does not have caches
+ }
+
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4a4c6c8..94152cd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -110,17 +110,17 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void freeCaches() {
+ /*package*/ static void nFreeCaches() {
// nothing to be done here.
}
@LayoutlibDelegate
- /*package*/ static void freeTextLayoutCaches() {
+ /*package*/ static void nFreeTextLayoutCaches() {
// nothing to be done here yet.
}
@LayoutlibDelegate
- /*package*/ static long initRaster(@Nullable Bitmap bitmap) {
+ /*package*/ static long nInitRaster(@Nullable Bitmap bitmap) {
long nativeBitmapOrZero = 0;
if (bitmap != null) {
nativeBitmapOrZero = bitmap.getNativeInstance();
@@ -142,7 +142,7 @@
}
@LayoutlibDelegate
- public static void native_setBitmap(long canvas, Bitmap bitmap) {
+ public static void nSetBitmap(long canvas, Bitmap bitmap) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
if (canvasDelegate == null || bitmapDelegate==null) {
@@ -153,7 +153,7 @@
}
@LayoutlibDelegate
- public static boolean native_isOpaque(long nativeCanvas) {
+ public static boolean nIsOpaque(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -164,10 +164,10 @@
}
@LayoutlibDelegate
- public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+ public static void nSetHighContrastText(long nativeCanvas, boolean highContrastText){}
@LayoutlibDelegate
- public static int native_getWidth(long nativeCanvas) {
+ public static int nGetWidth(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -178,7 +178,7 @@
}
@LayoutlibDelegate
- public static int native_getHeight(long nativeCanvas) {
+ public static int nGetHeight(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -189,7 +189,7 @@
}
@LayoutlibDelegate
- public static int native_save(long nativeCanvas, int saveFlags) {
+ public static int nSave(long nativeCanvas, int saveFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -200,7 +200,7 @@
}
@LayoutlibDelegate
- public static int native_saveLayer(long nativeCanvas, float l,
+ public static int nSaveLayer(long nativeCanvas, float l,
float t, float r, float b,
long paint, int layerFlags) {
// get the delegate from the native int.
@@ -219,7 +219,7 @@
}
@LayoutlibDelegate
- public static int native_saveLayerAlpha(long nativeCanvas, float l,
+ public static int nSaveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
// get the delegate from the native int.
@@ -232,7 +232,7 @@
}
@LayoutlibDelegate
- public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+ public static void nRestore(long nativeCanvas, boolean throwOnUnderflow) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -244,7 +244,7 @@
}
@LayoutlibDelegate
- public static void native_restoreToCount(long nativeCanvas, int saveCount,
+ public static void nRestoreToCount(long nativeCanvas, int saveCount,
boolean throwOnUnderflow) {
// FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
@@ -257,7 +257,7 @@
}
@LayoutlibDelegate
- public static int native_getSaveCount(long nativeCanvas) {
+ public static int nGetSaveCount(long nativeCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -268,7 +268,7 @@
}
@LayoutlibDelegate
- public static void native_translate(long nativeCanvas, float dx, float dy) {
+ public static void nTranslate(long nativeCanvas, float dx, float dy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -279,7 +279,7 @@
}
@LayoutlibDelegate
- public static void native_scale(long nativeCanvas, float sx, float sy) {
+ public static void nScale(long nativeCanvas, float sx, float sy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -290,7 +290,7 @@
}
@LayoutlibDelegate
- public static void native_rotate(long nativeCanvas, float degrees) {
+ public static void nRotate(long nativeCanvas, float degrees) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -301,7 +301,7 @@
}
@LayoutlibDelegate
- public static void native_skew(long nativeCanvas, float kx, float ky) {
+ public static void nSkew(long nativeCanvas, float kx, float ky) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -325,7 +325,7 @@
}
@LayoutlibDelegate
- public static void native_concat(long nCanvas, long nMatrix) {
+ public static void nConcat(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
if (canvasDelegate == null) {
@@ -353,7 +353,7 @@
}
@LayoutlibDelegate
- public static void native_setMatrix(long nCanvas, long nMatrix) {
+ public static void nSetMatrix(long nCanvas, long nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
if (canvasDelegate == null) {
@@ -383,7 +383,7 @@
}
@LayoutlibDelegate
- public static boolean native_clipRect(long nCanvas,
+ public static boolean nClipRect(long nCanvas,
float left, float top,
float right, float bottom,
int regionOp) {
@@ -397,7 +397,7 @@
}
@LayoutlibDelegate
- public static boolean native_clipPath(long nativeCanvas,
+ public static boolean nClipPath(long nativeCanvas,
long nativePath,
int regionOp) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -414,7 +414,7 @@
}
@LayoutlibDelegate
- public static boolean native_clipRegion(long nativeCanvas,
+ public static boolean nClipRegion(long nativeCanvas,
long nativeRegion,
int regionOp) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -431,7 +431,7 @@
}
@LayoutlibDelegate
- public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
+ public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
@@ -446,7 +446,7 @@
}
@LayoutlibDelegate
- public static boolean native_getClipBounds(long nativeCanvas,
+ public static boolean nGetClipBounds(long nativeCanvas,
Rect bounds) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -467,7 +467,7 @@
}
@LayoutlibDelegate
- public static void native_getCTM(long canvas, long matrix) {
+ public static void nGetCTM(long canvas, long matrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
if (canvasDelegate == null) {
@@ -484,13 +484,13 @@
}
@LayoutlibDelegate
- public static boolean native_quickReject(long nativeCanvas, long path) {
+ public static boolean nQuickReject(long nativeCanvas, long path) {
// FIXME properly implement quickReject
return false;
}
@LayoutlibDelegate
- public static boolean native_quickReject(long nativeCanvas,
+ public static boolean nQuickReject(long nativeCanvas,
float left, float top,
float right, float bottom) {
// FIXME properly implement quickReject
@@ -498,7 +498,7 @@
}
@LayoutlibDelegate
- public static void native_drawColor(long nativeCanvas, final int color, final int mode) {
+ public static void nDrawColor(long nativeCanvas, final int color, final int mode) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -529,14 +529,14 @@
}
@LayoutlibDelegate
- public static void native_drawPaint(long nativeCanvas, long paint) {
+ public static void nDrawPaint(long nativeCanvas, long paint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Canvas.drawPaint is not supported.", null, null /*data*/);
}
@LayoutlibDelegate
- public static void native_drawPoint(long nativeCanvas, float x, float y,
+ public static void nDrawPoint(long nativeCanvas, float x, float y,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -544,7 +544,7 @@
}
@LayoutlibDelegate
- public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+ public static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -552,7 +552,7 @@
}
@LayoutlibDelegate
- public static void native_drawLine(long nativeCanvas,
+ public static void nDrawLine(long nativeCanvas,
final float startX, final float startY, final float stopX, final float stopY,
long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -565,7 +565,7 @@
}
@LayoutlibDelegate
- public static void native_drawLines(long nativeCanvas,
+ public static void nDrawLines(long nativeCanvas,
final float[] pts, final int offset, final int count,
long nativePaint) {
draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
@@ -581,7 +581,7 @@
}
@LayoutlibDelegate
- public static void native_drawRect(long nativeCanvas,
+ public static void nDrawRect(long nativeCanvas,
final float left, final float top, final float right, final float bottom, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -607,7 +607,7 @@
}
@LayoutlibDelegate
- public static void native_drawOval(long nativeCanvas, final float left,
+ public static void nDrawOval(long nativeCanvas, final float left,
final float top, final float right, final float bottom, long paint) {
if (right > left && bottom > top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -634,15 +634,15 @@
}
@LayoutlibDelegate
- public static void native_drawCircle(long nativeCanvas,
+ public static void nDrawCircle(long nativeCanvas,
float cx, float cy, float radius, long paint) {
- native_drawOval(nativeCanvas,
+ nDrawOval(nativeCanvas,
cx - radius, cy - radius, cx + radius, cy + radius,
paint);
}
@LayoutlibDelegate
- public static void native_drawArc(long nativeCanvas,
+ public static void nDrawArc(long nativeCanvas,
final float left, final float top, final float right, final float bottom,
final float startAngle, final float sweep,
final boolean useCenter, long paint) {
@@ -674,7 +674,7 @@
}
@LayoutlibDelegate
- public static void native_drawRoundRect(long nativeCanvas,
+ public static void nDrawRoundRect(long nativeCanvas,
final float left, final float top, final float right, final float bottom,
final float rx, final float ry, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -704,7 +704,7 @@
}
@LayoutlibDelegate
- public static void native_drawPath(long nativeCanvas, long path, long paint) {
+ public static void nDrawPath(long nativeCanvas, long path, long paint) {
final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
if (pathDelegate == null) {
return;
@@ -756,7 +756,7 @@
}
@LayoutlibDelegate
- public static void native_drawRegion(long nativeCanvas, long nativeRegion,
+ public static void nDrawRegion(long nativeCanvas, long nativeRegion,
long nativePaint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -764,7 +764,7 @@
}
@LayoutlibDelegate
- public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+ public static void nDrawNinePatch(Canvas thisCanvas, long nativeCanvas,
long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
final float dstRight, final float dstBottom, long nativePaintOrZero,
final int screenDensity, final int bitmapDensity) {
@@ -811,7 +811,7 @@
}
@LayoutlibDelegate
- public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+ public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float left, float top,
long nativePaintOrZero,
int canvasDensity,
@@ -833,7 +833,7 @@
}
@LayoutlibDelegate
- public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+ public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -849,7 +849,7 @@
}
@LayoutlibDelegate
- public static void native_drawBitmap(long nativeCanvas, int[] colors,
+ public static void nDrawBitmap(long nativeCanvas, int[] colors,
int offset, int stride, final float x,
final float y, int width, int height,
boolean hasAlpha,
@@ -936,25 +936,25 @@
}
@LayoutlibDelegate
- public static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+ public static void nDrawText(long nativeCanvas, char[] text, int index, int count,
float startX, float startY, int flags, long paint, long typeface) {
drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
paint, typeface);
}
@LayoutlibDelegate
- public static void native_drawText(long nativeCanvas, String text,
+ public static void nDrawText(long nativeCanvas, String text,
int start, int end, float x, float y, final int flags, long paint,
long typeface) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
+ nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
}
@LayoutlibDelegate
- public static void native_drawTextRun(long nativeCanvas, String text,
+ public static void nDrawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, boolean isRtl, long paint, long typeface) {
int count = end - start;
@@ -965,14 +965,14 @@
}
@LayoutlibDelegate
- public static void native_drawTextRun(long nativeCanvas, char[] text,
+ public static void nDrawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
float x, float y, boolean isRtl, long paint, long typeface) {
drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
}
@LayoutlibDelegate
- public static void native_drawTextOnPath(long nativeCanvas,
+ public static void nDrawTextOnPath(long nativeCanvas,
char[] text, int index,
int count, long path,
float hOffset,
@@ -984,7 +984,7 @@
}
@LayoutlibDelegate
- public static void native_drawTextOnPath(long nativeCanvas,
+ public static void nDrawTextOnPath(long nativeCanvas,
String text, long path,
float hOffset,
float vOffset,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index a503e50..354f919 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -27,6 +27,8 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
+import libcore.util.NativeAllocationRegistry_Delegate;
+
/**
* Delegate implementing the native methods of android.graphics.Matrix
*
@@ -47,6 +49,7 @@
// ---- delegate manager ----
private static final DelegateManager<Matrix_Delegate> sManager =
new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
+ private static long sFinalizer = -1;
// ---- delegate data ----
private float mValues[] = new float[MATRIX_SIZE];
@@ -174,7 +177,7 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static long native_create(long native_src_or_zero) {
+ /*package*/ static long nCreate(long native_src_or_zero) {
// create the delegate
Matrix_Delegate newDelegate = new Matrix_Delegate();
@@ -193,7 +196,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_isIdentity(long native_object) {
+ /*package*/ static boolean nIsIdentity(long native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return false;
@@ -203,7 +206,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_isAffine(long native_object) {
+ /*package*/ static boolean nIsAffine(long native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return true;
@@ -213,7 +216,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_rectStaysRect(long native_object) {
+ /*package*/ static boolean nRectStaysRect(long native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return true;
@@ -223,7 +226,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_reset(long native_object) {
+ /*package*/ static void nReset(long native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -233,7 +236,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_set(long native_object, long other) {
+ /*package*/ static void nSet(long native_object, long other) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -248,7 +251,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void nSetTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -258,7 +261,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setScale(long native_object, float sx, float sy,
+ /*package*/ static void nSetScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -269,7 +272,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setScale(long native_object, float sx, float sy) {
+ /*package*/ static void nSetScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -287,7 +290,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setRotate(long native_object, float degrees, float px, float py) {
+ /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -297,7 +300,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setRotate(long native_object, float degrees) {
+ /*package*/ static void nSetRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -307,7 +310,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue,
+ /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -326,7 +329,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue) {
+ /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -336,7 +339,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setSkew(long native_object, float kx, float ky,
+ /*package*/ static void nSetSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -347,7 +350,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setSkew(long native_object, float kx, float ky) {
+ /*package*/ static void nSetSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -365,12 +368,12 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setConcat(long native_object, long a, long b) {
+ /*package*/ static void nSetConcat(long native_object, long a, long b) {
if (a == native_object) {
- native_preConcat(native_object, b);
+ nPreConcat(native_object, b);
return;
} else if (b == native_object) {
- native_postConcat(native_object, a);
+ nPostConcat(native_object, a);
return;
}
@@ -383,7 +386,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void nPreTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.preTransform(getTranslate(dx, dy));
@@ -391,7 +394,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preScale(long native_object, float sx, float sy,
+ /*package*/ static void nPreScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -400,7 +403,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preScale(long native_object, float sx, float sy) {
+ /*package*/ static void nPreScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.preTransform(getScale(sx, sy));
@@ -408,7 +411,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preRotate(long native_object, float degrees,
+ /*package*/ static void nPreRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -417,7 +420,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preRotate(long native_object, float degrees) {
+ /*package*/ static void nPreRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -430,7 +433,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preSkew(long native_object, float kx, float ky,
+ /*package*/ static void nPreSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -439,7 +442,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preSkew(long native_object, float kx, float ky) {
+ /*package*/ static void nPreSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.preTransform(getSkew(kx, ky));
@@ -447,7 +450,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_preConcat(long native_object, long other_matrix) {
+ /*package*/ static void nPreConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
Matrix_Delegate other = sManager.getDelegate(other_matrix);
if (d != null && other != null) {
@@ -456,7 +459,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void nPostTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.postTransform(getTranslate(dx, dy));
@@ -464,7 +467,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postScale(long native_object, float sx, float sy,
+ /*package*/ static void nPostScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -473,7 +476,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postScale(long native_object, float sx, float sy) {
+ /*package*/ static void nPostScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.postTransform(getScale(sx, sy));
@@ -481,7 +484,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postRotate(long native_object, float degrees,
+ /*package*/ static void nPostRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -490,7 +493,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postRotate(long native_object, float degrees) {
+ /*package*/ static void nPostRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.postTransform(getRotate(degrees));
@@ -498,7 +501,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postSkew(long native_object, float kx, float ky,
+ /*package*/ static void nPostSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
@@ -507,7 +510,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postSkew(long native_object, float kx, float ky) {
+ /*package*/ static void nPostSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d != null) {
d.postTransform(getSkew(kx, ky));
@@ -515,7 +518,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_postConcat(long native_object, long other_matrix) {
+ /*package*/ static void nPostConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
Matrix_Delegate other = sManager.getDelegate(other_matrix);
if (d != null && other != null) {
@@ -524,7 +527,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_setRectToRect(long native_object, RectF src,
+ /*package*/ static boolean nSetRectToRect(long native_object, RectF src,
RectF dst, int stf) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -589,7 +592,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_setPolyToPoly(long native_object, float[] src, int srcIndex,
+ /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex,
float[] dst, int dstIndex, int pointCount) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -599,7 +602,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_invert(long native_object, long inverse) {
+ /*package*/ static boolean nInvert(long native_object, long inverse) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return false;
@@ -627,7 +630,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_mapPoints(long native_object, float[] dst, int dstIndex,
+ /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex,
float[] src, int srcIndex, int ptCount, boolean isPts) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -642,7 +645,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_mapRect(long native_object, RectF dst, RectF src) {
+ /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return false;
@@ -652,7 +655,7 @@
}
@LayoutlibDelegate
- /*package*/ static float native_mapRadius(long native_object, float radius) {
+ /*package*/ static float nMapRadius(long native_object, float radius) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return 0.f;
@@ -667,7 +670,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_getValues(long native_object, float[] values) {
+ /*package*/ static void nGetValues(long native_object, float[] values) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -677,7 +680,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setValues(long native_object, float[] values) {
+ /*package*/ static void nSetValues(long native_object, float[] values) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
return;
@@ -687,7 +690,7 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_equals(long native_a, long native_b) {
+ /*package*/ static boolean nEquals(long native_a, long native_b) {
Matrix_Delegate a = sManager.getDelegate(native_a);
if (a == null) {
return false;
@@ -708,8 +711,13 @@
}
@LayoutlibDelegate
- /*package*/ static void finalizer(long native_instance) {
- sManager.removeJavaReferenceFor(native_instance);
+ /*package*/ static long nGetNativeFinalizer() {
+ synchronized (Matrix_Delegate.class) {
+ if (sFinalizer == -1) {
+ sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
+ }
+ }
+ return sFinalizer;
}
// ---- Private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 33296e1..0bbe33d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -261,7 +261,7 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static int nGetFlags(Paint thisPaint, long nativePaint) {
+ /*package*/ static int nGetFlags(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -274,7 +274,7 @@
@LayoutlibDelegate
- /*package*/ static void nSetFlags(Paint thisPaint, long nativePaint, int flags) {
+ /*package*/ static void nSetFlags(long nativePaint, int flags) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -285,12 +285,12 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter) {
+ /*package*/ static void nSetFilterBitmap(long nativePaint, boolean filter) {
setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter);
}
@LayoutlibDelegate
- /*package*/ static int nGetHinting(Paint thisPaint, long nativePaint) {
+ /*package*/ static int nGetHinting(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -301,7 +301,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetHinting(Paint thisPaint, long nativePaint, int mode) {
+ /*package*/ static void nSetHinting(long nativePaint, int mode) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -312,46 +312,46 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa) {
+ /*package*/ static void nSetAntiAlias(long nativePaint, boolean aa) {
setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa);
}
@LayoutlibDelegate
- /*package*/ static void nSetSubpixelText(Paint thisPaint, long nativePaint,
+ /*package*/ static void nSetSubpixelText(long nativePaint,
boolean subpixelText) {
setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
}
@LayoutlibDelegate
- /*package*/ static void nSetUnderlineText(Paint thisPaint, long nativePaint,
+ /*package*/ static void nSetUnderlineText(long nativePaint,
boolean underlineText) {
setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
}
@LayoutlibDelegate
- /*package*/ static void nSetStrikeThruText(Paint thisPaint, long nativePaint,
+ /*package*/ static void nSetStrikeThruText(long nativePaint,
boolean strikeThruText) {
setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
}
@LayoutlibDelegate
- /*package*/ static void nSetFakeBoldText(Paint thisPaint, long nativePaint,
+ /*package*/ static void nSetFakeBoldText(long nativePaint,
boolean fakeBoldText) {
setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
}
@LayoutlibDelegate
- /*package*/ static void nSetDither(Paint thisPaint, long nativePaint, boolean dither) {
+ /*package*/ static void nSetDither(long nativePaint, boolean dither) {
setFlag(nativePaint, Paint.DITHER_FLAG, dither);
}
@LayoutlibDelegate
- /*package*/ static void nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText) {
+ /*package*/ static void nSetLinearText(long nativePaint, boolean linearText) {
setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText);
}
@LayoutlibDelegate
- /*package*/ static int nGetColor(Paint thisPaint, long nativePaint) {
+ /*package*/ static int nGetColor(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -362,7 +362,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetColor(Paint thisPaint, long nativePaint, int color) {
+ /*package*/ static void nSetColor(long nativePaint, int color) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -373,7 +373,7 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetAlpha(Paint thisPaint, long nativePaint) {
+ /*package*/ static int nGetAlpha(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -384,7 +384,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetAlpha(Paint thisPaint, long nativePaint, int a) {
+ /*package*/ static void nSetAlpha(long nativePaint, int a) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -395,7 +395,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetStrokeWidth(Paint thisPaint, long nativePaint) {
+ /*package*/ static float nGetStrokeWidth(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -406,7 +406,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetStrokeWidth(Paint thisPaint, long nativePaint, float width) {
+ /*package*/ static void nSetStrokeWidth(long nativePaint, float width) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -417,7 +417,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetStrokeMiter(Paint thisPaint, long nativePaint) {
+ /*package*/ static float nGetStrokeMiter(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -428,7 +428,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter) {
+ /*package*/ static void nSetStrokeMiter(long nativePaint, float miter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -455,14 +455,14 @@
}
@LayoutlibDelegate
- /*package*/ static boolean nIsElegantTextHeight(Paint thisPaint, long nativePaint) {
+ /*package*/ static boolean nIsElegantTextHeight(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
}
@LayoutlibDelegate
- /*package*/ static void nSetElegantTextHeight(Paint thisPaint, long nativePaint,
+ /*package*/ static void nSetElegantTextHeight(long nativePaint,
boolean elegant) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -474,7 +474,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetTextSize(Paint thisPaint, long nativePaint) {
+ /*package*/ static float nGetTextSize(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -485,7 +485,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetTextSize(Paint thisPaint, long nativePaint, float textSize) {
+ /*package*/ static void nSetTextSize(long nativePaint, float textSize) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -499,7 +499,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetTextScaleX(Paint thisPaint, long nativePaint) {
+ /*package*/ static float nGetTextScaleX(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -510,7 +510,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX) {
+ /*package*/ static void nSetTextScaleX(long nativePaint, float scaleX) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -524,7 +524,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetTextSkewX(Paint thisPaint, long nativePaint) {
+ /*package*/ static float nGetTextSkewX(long nativePaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -535,7 +535,7 @@
}
@LayoutlibDelegate
- /*package*/ static void nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX) {
+ /*package*/ static void nSetTextSkewX(long nativePaint, float skewX) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -549,7 +549,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nAscent(Paint thisPaint, long nativePaint, long nativeTypeface) {
+ /*package*/ static float nAscent(long nativePaint, long nativeTypeface) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -566,7 +566,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nDescent(Paint thisPaint, long nativePaint, long nativeTypeface) {
+ /*package*/ static float nDescent(long nativePaint, long nativeTypeface) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
if (delegate == null) {
@@ -583,7 +583,7 @@
}
@LayoutlibDelegate
- /*package*/ static float nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface,
+ /*package*/ static float nGetFontMetrics(long nativePaint, long nativeTypeface,
FontMetrics metrics) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -595,7 +595,7 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetFontMetricsInt(Paint thisPaint, long nativePaint,
+ /*package*/ static int nGetFontMetricsInt(long nativePaint,
long nativeTypeface, FontMetricsInt fmi) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -998,7 +998,7 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, char[] text,
+ /*package*/ static int nGetTextRunCursor(long native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1007,7 +1007,7 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, String text,
+ /*package*/ static int nGetTextRunCursor(long native_object, String text,
int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index 3e81e83..9904263 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -141,12 +141,12 @@
long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
- Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
- Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top);
+ Canvas_Delegate.nSave(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+ Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.left, bounds.top);
if (needsMirroring) {
- Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0);
- Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f);
+ Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.width(), 0);
+ Canvas_Delegate.nScale(canvasWrapperPtr, -1.0f, 1.0f);
}
// At this point, canvas has been translated to the right position.
@@ -155,7 +155,7 @@
bounds.offsetTo(0, 0);
nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
- Canvas_Delegate.native_restore(canvasWrapperPtr, true);
+ Canvas_Delegate.nRestore(canvasWrapperPtr, true);
return bounds.width() * bounds.height();
}
@@ -1108,7 +1108,7 @@
currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
// Save the current clip information, which is local to this group.
- Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+ Canvas_Delegate.nSave(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
// Draw the group tree in the same order as the XML file.
for (int i = 0; i < currentGroup.mChildren.size(); i++) {
Object child = currentGroup.mChildren.get(i);
@@ -1121,7 +1121,7 @@
drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
}
}
- Canvas_Delegate.native_restore(canvasPtr, true);
+ Canvas_Delegate.nRestore(canvasPtr, true);
}
public void draw(long canvasPtr, long filterPtr, int w, int h) {
@@ -1153,7 +1153,7 @@
if (VPath.isClipPath()) {
mRenderPath.addPath(path, mFinalPathMatrix);
- Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op
+ Canvas_Delegate.nClipPath(canvasPtr, mRenderPath.mNativePath, Op
.INTERSECT.nativeInt);
} else {
VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
@@ -1197,7 +1197,7 @@
fillPaintDelegate.setColorFilter(filterPtr);
fillPaintDelegate.setShader(fullPath.mFillGradient);
Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType);
- Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
+ Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
.getNativeInstance());
}
@@ -1228,7 +1228,7 @@
final float finalStrokeScale = minScale * matrixScale;
strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
strokePaintDelegate.setShader(fullPath.mStrokeGradient);
- Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
+ Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
.getNativeInstance());
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index e4cbb2f..3471165 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -145,4 +145,10 @@
public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
return null;
}
+
+ @Override
+ public boolean refresh(String callingPkg, Uri url, Bundle args,
+ ICancellationSignal cancellationSignal) throws RemoteException {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/tests/res/empty.xml b/tools/layoutlib/bridge/tests/res/empty.xml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/empty.xml
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
index 4561e1b..4781660 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
@@ -19,12 +19,12 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 22
- buildToolsVersion '21.1.2'
+ compileSdkVersion 25
+ buildToolsVersion '25.0.0'
defaultConfig {
applicationId 'com.android.layoutlib.test.myapplication'
minSdkVersion 21
- targetSdkVersion 22
+ targetSdkVersion 25
versionCode 1
versionName '1.0'
}
@@ -34,6 +34,9 @@
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ lintOptions {
+ abortOnError false
+ }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class
index e0373cb..f73528a 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/ArraysCheckWidget.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
deleted file mode 100644
index c363055..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
deleted file mode 100644
index edda3de..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
index ec42017..5bb04fc 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class
new file mode 100644
index 0000000..ff699d1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$color.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
index 0e208f2..a3931b8 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
index 2b77af3..e293677 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
index fd01b44..d6268bf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class
index 91cf5b6..08b98fb 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$integer.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
index 6c351da..f9be1ca 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
index aecbff6..6874b49e 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
index fc3f236..a4205a8 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
index 83ad35b..4fb3b61 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
index 6d7c719..dba67fd 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 9bf302a..f274dbf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java
index 41d75de..e7f22bf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/ArraysCheckWidget.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.layoutlib.test.myapplication;
import android.content.Context;
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
deleted file mode 100644
index 80bbaf1..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.layoutlib.test.myapplication;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.CalendarView;
-
-public class CustomCalendar extends CalendarView {
- public CustomCalendar(Context context) {
- super(context);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- setDate(871703200000L, false, true);
- }
-}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java
deleted file mode 100644
index cb750f4..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.layoutlib.test.myapplication;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.DatePicker;
-
-public class CustomDate extends DatePicker {
- public CustomDate(Context context) {
- super(context);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- public CustomDate(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- private void init() {
- init(2015, 0, 20, null);
- }
-}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java
new file mode 100644
index 0000000..3b819e5
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomCalendar.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.test.myapplication.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.CalendarView;
+
+public class CustomCalendar extends CalendarView {
+ public CustomCalendar(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ setDate(871732800000L, false, true);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java
new file mode 100644
index 0000000..f3877f1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/CustomDate.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.test.myapplication.widgets;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.DatePicker;
+
+public class CustomDate extends DatePicker {
+ public CustomDate(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ init(2015, 0, 20, null);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java
new file mode 100644
index 0000000..58ad46d
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package contains custom widgets used to set a specific time for the DayTimePicker during
+ * testing.
+ * The classes here are both used from the Android project and from the Bridge test project.
+ */
+package com.android.layoutlib.test.myapplication.widgets;
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml
index 50646ab..e9aa9e1 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/array_check.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<com.android.layoutlib.test.myapplication.ArraysCheckWidget xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.layoutlib.test.myapplication.ArraysCheckWidget
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
index c1f663e..ff14ce0 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
@@ -15,10 +15,10 @@
android:checked="true"
android:layout_gravity="center"
/>
- <com.android.layoutlib.test.myapplication.CustomDate
+ <com.android.layoutlib.test.myapplication.widgets.CustomDate
android:layout_width="100dp"
android:layout_height="wrap_content"/>
- <com.android.layoutlib.test.myapplication.CustomCalendar
+ <com.android.layoutlib.test.myapplication.widgets.CustomCalendar
android:layout_width="200dp"
android:layout_gravity="center_horizontal"
android:layout_height="200dp"/>
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
index 88c9cbc..c8a5fec 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
@@ -3,7 +3,7 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
<item name="myattr">@integer/ten</item>
- <!-- Customize your theme here. -->
+ <item name="android:animateFirstView">false</item>
</style>
</resources>
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index e7c6cc9..5423e87 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -39,6 +39,7 @@
import com.android.resources.Density;
import com.android.resources.Navigation;
import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.java.System_Delegate;
import com.android.utils.ILogger;
import org.junit.AfterClass;
@@ -51,6 +52,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageInstaller.Session;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -58,11 +60,28 @@
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.ref.WeakReference;
+import java.net.MalformedURLException;
import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.CopyOption;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiPredicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
import com.google.android.collect.Lists;
@@ -105,6 +124,8 @@
private static final String APP_TEST_DIR = "/testApp/MyApplication";
/** Location of the app's res dir inside {@link #TEST_RES_DIR}*/
private static final String APP_TEST_RES = APP_TEST_DIR + "/src/main/res";
+ private static final String APP_CLASSES_LOCATION =
+ APP_TEST_DIR + "/build/intermediates/classes/debug/";
private static LayoutLog sLayoutLibLog;
private static FrameworkResources sFrameworkRepo;
@@ -115,6 +136,11 @@
/** List of log messages generated by a render call. It can be used to find specific errors */
private static ArrayList<String> sRenderMessages = Lists.newArrayList();
+ // Default class loader with access to the app classes
+ private ClassLoader mDefaultClassLoader =
+ new URLClassLoader(new URL[]{this.getClass().getResource(APP_CLASSES_LOCATION)},
+ getClass().getClassLoader());
+
@Rule
public TestWatcher sRenderMessageWatcher = new TestWatcher() {
@Override
@@ -192,6 +218,7 @@
}
File[] hosts = host.listFiles(path -> path.isDirectory() &&
(path.getName().startsWith("linux-") || path.getName().startsWith("darwin-")));
+ assert hosts != null;
for (File hostOut : hosts) {
String platformDir = getPlatformDirFromHostOut(hostOut);
if (platformDir != null) {
@@ -213,6 +240,7 @@
// We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7)
return path.isDirectory() && path.getName().startsWith("sdk");
});
+ assert sdkDirs != null;
for (File dir : sdkDirs) {
String platformDir = getPlatformDirFromHostOutSdkSdk(dir);
if (platformDir != null) {
@@ -225,6 +253,7 @@
private static String getPlatformDirFromHostOutSdkSdk(File sdkDir) {
File[] possibleSdks = sdkDir.listFiles(
path -> path.isDirectory() && path.getName().contains("android-sdk"));
+ assert possibleSdks != null;
for (File possibleSdk : possibleSdks) {
File platformsDir = new File(possibleSdk, "platforms");
File[] platforms = platformsDir.listFiles(
@@ -309,21 +338,51 @@
/** Test activity.xml */
@Test
public void testActivity() throws ClassNotFoundException {
- try {
- renderAndVerify("activity.xml", "activity.png");
- } catch (AssertionError e) {
- // This is a KI in CalendarWidget and DatePicker rendering.
- // Tracker bug: http://b.android.com/214370
- if (!e.getLocalizedMessage().startsWith("Images differ (by 6.5%)")) {
- throw e;
- }
+ renderAndVerify("activity.xml", "activity.png");
+ }
+
+ private static void gc() {
+ // See RuntimeUtil#gc in jlibs (http://jlibs.in/)
+ Object obj = new Object();
+ WeakReference ref = new WeakReference<>(obj);
+ //noinspection UnusedAssignment
+ obj = null;
+ while(ref.get() != null) {
+ System.gc();
+ System.runFinalization();
}
+
+ System.gc();
+ System.runFinalization();
+ }
+
+ /** Test allwidgets.xml */
+ @Test
+ public void testAllWidgets() throws ClassNotFoundException {
+ renderAndVerify("allwidgets.xml", "allwidgets.png");
+
+ // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+ sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
+ }
+
+ @Test
+ public void testArrayCheck() throws ClassNotFoundException {
+ renderAndVerify("array_check.xml", "array_check.png");
+ }
+
+ @Test
+ public void testAllWidgetsTablet() throws ClassNotFoundException {
+ renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
+
+ // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+ sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
}
@Test
public void testActivityActionBar() throws ClassNotFoundException {
LayoutPullParser parser = createLayoutPullParser("simple_activity.xml");
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
@@ -349,42 +408,6 @@
renderAndVerify(params, "simple_activity.png");
}
- /** Test allwidgets.xml */
- @Test
- public void testAllWidgets() throws ClassNotFoundException {
- renderAndVerify("allwidgets.xml", "allwidgets.png");
-
- // We expect fidelity warnings for Path.isConvex. Fail for anything else.
- sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
- }
-
- @Test
- public void testArrayCheck() throws ClassNotFoundException {
- renderAndVerify("array_check.xml", "array_check.png");
- }
-
- @Test
- public void testAllWidgetsTablet() throws ClassNotFoundException {
- renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
-
- // We expect fidelity warnings for Path.isConvex. Fail for anything else.
- sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
- }
-
- private static void gc() {
- // See RuntimeUtil#gc in jlibs (http://jlibs.in/)
- Object obj = new Object();
- WeakReference ref = new WeakReference<Object>(obj);
- obj = null;
- while(ref.get() != null) {
- System.gc();
- System.runFinalization();
- }
-
- System.gc();
- System.runFinalization();
- }
-
@AfterClass
public static void tearDown() {
sLayoutLibLog = null;
@@ -405,7 +428,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser("expand_vert_layout.xml");
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
ConfigGenerator customConfigGenerator = new ConfigGenerator()
@@ -439,7 +463,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser("indeterminate_progressbar.xml");
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
@@ -464,7 +489,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser("vector_drawable.xml");
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
@@ -482,7 +508,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser("vector_drawable_android.xml");
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
@@ -498,7 +525,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser("scrolled.xml");
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
@@ -509,6 +537,7 @@
RenderResult result = renderAndVerify(params, "scrolled.png");
assertNotNull(result);
+ assertNotNull(result.getResult());
assertTrue(result.getResult().isSuccess());
ViewInfo rootLayout = result.getRootViews().get(0);
@@ -528,7 +557,15 @@
@Test
public void testGetResourceNameVariants() throws Exception {
// Setup
- SessionParams params = createSessionParams("empty.xml", ConfigGenerator.NEXUS_4);
+ // Create the layout pull parser for our resources (empty.xml can not be part of the test
+ // app as it won't compile).
+ LayoutPullParser parser = new LayoutPullParser("/empty.xml");
+ // Create LayoutLibCallback.
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+ layoutLibCallback.initResources();
+ SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_4,
+ layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
@@ -570,6 +607,8 @@
throws ClassNotFoundException {
// TODO: Set up action bar handler properly to test menu rendering.
// Create session params.
+ System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L));
+ System_Delegate.setNanosTime(TimeUnit.MILLISECONDS.toNanos(871732800000L));
RenderSession session = sBridge.createSession(params);
if (frameTimeNanos != -1) {
@@ -637,7 +676,8 @@
// Create the layout pull parser.
LayoutPullParser parser = createLayoutPullParser(layoutFileName);
// Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
layoutLibCallback.initResources();
// TODO: Set up action bar handler properly to test menu rendering.
// Create session params.
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index 96ae523..bae2dc0c 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -42,6 +42,9 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.Map;
import com.google.android.collect.Maps;
@@ -59,10 +62,11 @@
private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap();
private final ILogger mLog;
private final ActionBarCallback mActionBarCallback = new ActionBarCallback();
- private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION);
+ private final ClassLoader mModuleClassLoader;
- public LayoutLibTestCallback(ILogger logger) {
+ public LayoutLibTestCallback(ILogger logger, ClassLoader classLoader) {
mLog = logger;
+ mModuleClassLoader = classLoader;
}
public void initResources() throws ClassNotFoundException {
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java
deleted file mode 100644
index 110f4c8..0000000
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge.intensive.setup;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-
-import com.google.android.collect.Maps;
-
-/**
- * The ClassLoader to load the project's classes.
- */
-public class ModuleClassLoader extends ClassLoader {
-
- private final Map<String, Class<?>> mClasses = Maps.newHashMap();
- private final String mClassLocation;
-
- public ModuleClassLoader(String classLocation) {
- mClassLocation = classLocation;
- }
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- Class<?> aClass = mClasses.get(name);
- if (aClass != null) {
- return aClass;
- }
- String pathName = mClassLocation.concat(name.replace('.', '/')).concat(".class");
- InputStream classInputStream = getClass().getResourceAsStream(pathName);
- if (classInputStream == null) {
- throw new ClassNotFoundException("Unable to find class " + name + " at " + pathName);
- }
- byte[] data;
- try {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- int nRead;
- data = new byte[16384]; // 16k
- while ((nRead = classInputStream.read(data, 0, data.length)) != -1) {
- buffer.write(data, 0, nRead);
- }
- buffer.flush();
- data = buffer.toByteArray();
- } catch (IOException e) {
- // Wrap the exception with ClassNotFoundException so that caller can deal with it.
- throw new ClassNotFoundException("Unable to load class " + name, e);
- }
- aClass = defineClass(name, data, 0, data.length);
- mClasses.put(name, aClass);
- return aClass;
- }
-}
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
index ce877b3..09d95ff 100644
--- a/tools/preload2/Android.mk
+++ b/tools/preload2/Android.mk
@@ -5,7 +5,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
# To connect to devices (and take hprof dumps).
-LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt tools-common-prebuilt
# To process hprof dumps.
LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 017525b..9e897bf 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.ScanSettings;
@@ -58,10 +59,11 @@
int addOrUpdateNetwork(in WifiConfiguration config);
- int addPasspointManagementObject(String mo);
+ boolean addPasspointConfiguration(in PasspointConfiguration config);
- int modifyPasspointManagementObject(String fqdn,
- in List<PasspointManagementObjectDefinition> mos);
+ boolean removePasspointConfiguration(in String fqdn);
+
+ List<PasspointConfiguration> getPasspointConfigurations();
void queryPasspointIcon(long bssid, String fileName);
@@ -125,8 +127,6 @@
WifiConfiguration getWifiApConfiguration();
- WifiConfiguration buildWifiConfig(String uriString, String mimeType, in byte[] data);
-
void setWifiApConfiguration(in WifiConfiguration wifiConfig);
Messenger getWifiServiceMessenger();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 8d5efba..e48f7bdb 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -22,6 +22,7 @@
import android.net.NetworkUtils;
import android.text.TextUtils;
+import java.lang.Math;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
@@ -136,6 +137,15 @@
*/
public double rxSuccessRate;
+ private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
+ private static final long FILTER_TIME_CONSTANT = 3000;
+ /**
+ * This factor is used to adjust the rate output under the new algorithm
+ * such that the result is comparable to the previous algorithm.
+ */
+ private static final long OUTPUT_SCALE_FACTOR = 5000;
+ private long mLastPacketCountUpdateTimeStamp;
+
/**
* @hide
*/
@@ -157,10 +167,9 @@
public int score;
/**
- * TODO: get actual timestamp and calculate true rates
* @hide
*/
- public void updatePacketRates(WifiLinkLayerStats stats) {
+ public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) {
if (stats != null) {
long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
long txretries = stats.retries_be + stats.retries_bk
@@ -169,18 +178,28 @@
long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
+ stats.lostmpdu_vi + stats.lostmpdu_vo;
- if (txBad <= txbad
+ if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
+ && mLastPacketCountUpdateTimeStamp < timeStamp
+ && txBad <= txbad
&& txSuccess <= txgood
&& rxSuccess <= rxgood
&& txRetries <= txretries) {
- txBadRate = (txBadRate * 0.5)
- + ((double) (txbad - txBad) * 0.5);
- txSuccessRate = (txSuccessRate * 0.5)
- + ((double) (txgood - txSuccess) * 0.5);
- rxSuccessRate = (rxSuccessRate * 0.5)
- + ((double) (rxgood - rxSuccess) * 0.5);
- txRetriesRate = (txRetriesRate * 0.5)
- + ((double) (txretries - txRetries) * 0.5);
+ long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
+ double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
+ double currentSampleWeight = 1.0 - lastSampleWeight;
+
+ txBadRate = txBadRate * lastSampleWeight
+ + (txbad - txBad) * OUTPUT_SCALE_FACTOR / timeDelta
+ * currentSampleWeight;
+ txSuccessRate = txSuccessRate * lastSampleWeight
+ + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR / timeDelta
+ * currentSampleWeight;
+ rxSuccessRate = rxSuccessRate * lastSampleWeight
+ + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR / timeDelta
+ * currentSampleWeight;
+ txRetriesRate = txRetriesRate * lastSampleWeight
+ + (txretries - txRetries) * OUTPUT_SCALE_FACTOR / timeDelta
+ * currentSampleWeight;
} else {
txBadRate = 0;
txSuccessRate = 0;
@@ -191,6 +210,7 @@
txSuccess = txgood;
rxSuccess = rxgood;
txRetries = txretries;
+ mLastPacketCountUpdateTimeStamp = timeStamp;
} else {
txBad = 0;
txSuccess = 0;
@@ -200,6 +220,7 @@
txSuccessRate = 0;
rxSuccessRate = 0;
txRetriesRate = 0;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
}
@@ -243,6 +264,7 @@
mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/** @hide */
@@ -268,6 +290,7 @@
badRssiCount = 0;
linkStuckCount = 0;
score = 0;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
}
/**
@@ -295,6 +318,8 @@
txRetriesRate = source.txRetriesRate;
txSuccessRate = source.txSuccessRate;
rxSuccessRate = source.rxSuccessRate;
+ mLastPacketCountUpdateTimeStamp =
+ source.mLastPacketCountUpdateTimeStamp;
score = source.score;
badRssiCount = source.badRssiCount;
lowRssiCount = source.lowRssiCount;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 18a580e..674c161 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -26,6 +26,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -841,30 +842,50 @@
}
/**
- * Add a Hotspot 2.0 release 2 Management Object
- * @param mo The MO in XML form
- * @return -1 for failure
+ * Add a Passpoint configuration. The configuration provides a credential
+ * for connecting to Passpoint networks that are operated by the Passpoint
+ * service provider specified in the configuration.
+ *
+ * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
+ * Name). In the case when there is an existing configuration with the same base
+ * domain, the new configuration will replace the existing configuration.
+ *
+ * @param config The Passpoint configuration to be added
+ * @return true on success or false on failure
* @hide
*/
- public int addPasspointManagementObject(String mo) {
+ public boolean addPasspointConfiguration(PasspointConfiguration config) {
try {
- return mService.addPasspointManagementObject(mo);
+ return mService.addPasspointConfiguration(config);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Modify a Hotspot 2.0 release 2 Management Object
- * @param fqdn The FQDN of the service provider
- * @param mos A List of MO definitions to be updated
- * @return the number of nodes updated, or -1 for failure
+ * Remove a Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
+ *
+ * @param fqdn The FQDN of the passpoint configuration to be removed
+ * @return true on success or false on failure
* @hide
*/
- public int modifyPasspointManagementObject(String fqdn,
- List<PasspointManagementObjectDefinition> mos) {
+ public boolean removePasspointConfiguration(String fqdn) {
try {
- return mService.modifyPasspointManagementObject(fqdn, mos);
+ return mService.removePasspointConfiguration(fqdn);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return the list of installed Passpoint configurations.
+ *
+ * @return A list of PasspointConfiguration or null
+ * @hide
+ */
+ public List<PasspointConfiguration> getPasspointConfigurations() {
+ try {
+ return mService.getPasspointConfigurations();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1577,20 +1598,6 @@
}
/**
- * Builds a WifiConfiguration from Hotspot 2.0 MIME file.
- * @return AP details in WifiConfiguration
- *
- * @hide Dont open yet
- */
- public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
- try {
- return mService.buildWifiConfig(uriString, mimeType, data);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Sets the Wi-Fi AP Configuration.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
new file mode 100644
index 0000000..96db5d0
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
@@ -0,0 +1,473 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2;
+
+import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class for building PasspointConfiguration from an installation file.
+ *
+ * @hide
+ */
+public final class ConfigBuilder {
+ private static final String TAG = "ConfigBuilder";
+
+ // Header names.
+ private static final String CONTENT_TYPE = "Content-Type";
+ private static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+
+ // MIME types.
+ private static final String TYPE_MULTIPART_MIXED = "multipart/mixed";
+ private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config";
+ private static final String TYPE_PASSPOINT_PROFILE = "application/x-passpoint-profile";
+ private static final String TYPE_CA_CERT = "application/x-x509-ca-cert";
+ private static final String TYPE_PKCS12 = "application/x-pkcs12";
+
+ private static final String ENCODING_BASE64 = "base64";
+ private static final String BOUNDARY = "boundary=";
+
+ /**
+ * Class represent a MIME (Multipurpose Internet Mail Extension) part.
+ */
+ private static class MimePart {
+ /**
+ * Content type of the part.
+ */
+ public String type = null;
+
+ /**
+ * Decoded data.
+ */
+ public byte[] data = null;
+
+ /**
+ * Flag indicating if this is the last part (ending with --{boundary}--).
+ */
+ public boolean isLast = false;
+ }
+
+ /**
+ * Class represent the MIME (Multipurpose Internet Mail Extension) header.
+ */
+ private static class MimeHeader {
+ /**
+ * Content type.
+ */
+ public String contentType = null;
+
+ /**
+ * Boundary string (optional), only applies for the outter MIME header.
+ */
+ public String boundary = null;
+
+ /**
+ * Encoding type.
+ */
+ public String encodingType = null;
+ }
+
+
+ /**
+ * Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration}
+ * object. The configuration data is a base64 encoded MIME multipart data. Below is
+ * the format of the decoded message:
+ *
+ * Content-Type: multipart/mixed; boundary={boundary}
+ * Content-Transfer-Encoding: base64
+ *
+ * --{boundary}
+ * Content-Type: application/x-passpoint-profile
+ * Content-Transfer-Encoding: base64
+ *
+ * [base64 encoded Passpoint profile data]
+ * --{boundary}
+ * Content-Type: application/x-x509-ca-cert
+ * Content-Transfer-Encoding: base64
+ *
+ * [base64 encoded X509 CA certificate data]
+ * --{boundary}
+ * Content-Type: application/x-pkcs12
+ * Content-Transfer-Encoding: base64
+ *
+ * [base64 encoded PKCS#12 ASN.1 structure containing client certificate chain]
+ * --{boundary}
+ *
+ * @param mimeType MIME type of the encoded data.
+ * @param data A base64 encoded MIME multipart message containing the Passpoint profile
+ * (required), CA (Certificate Authority) certificate (optional), and client
+ * certificate chain (optional).
+ * @return {@link PasspointConfiguration}
+ */
+ public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) {
+ // Verify MIME type.
+ if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) {
+ Log.e(TAG, "Unexpected MIME type: " + mimeType);
+ return null;
+ }
+
+ try {
+ // Decode the data.
+ byte[] decodedData = Base64.decode(new String(data, StandardCharsets.ISO_8859_1),
+ Base64.DEFAULT);
+ Map<String, byte[]> mimeParts = parseMimeMultipartMessage(new LineNumberReader(
+ new InputStreamReader(new ByteArrayInputStream(decodedData),
+ StandardCharsets.ISO_8859_1)));
+ return createPasspointConfig(mimeParts);
+ } catch (IOException | IllegalArgumentException e) {
+ Log.e(TAG, "Failed to parse installation file: " + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Create a {@link PasspointConfiguration} object from list of MIME (Multipurpose Internet
+ * Mail Extension) parts.
+ *
+ * @param mimeParts Map of content type and content data.
+ * @return {@link PasspointConfiguration}
+ * @throws IOException
+ */
+ private static PasspointConfiguration createPasspointConfig(Map<String, byte[]> mimeParts)
+ throws IOException {
+ byte[] profileData = mimeParts.get(TYPE_PASSPOINT_PROFILE);
+ if (profileData == null) {
+ throw new IOException("Missing Passpoint Profile");
+ }
+
+ PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData));
+ if (config == null) {
+ throw new IOException("Failed to parse Passpoint profile");
+ }
+
+ // Credential is needed for storing the certificates and private client key.
+ if (config.credential == null) {
+ throw new IOException("Passpoint profile missing credential");
+ }
+
+ // Parse CA (Certificate Authority) certificate.
+ byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
+ if (caCertData != null) {
+ try {
+ config.credential.caCertificate = parseCACert(caCertData);
+ } catch (CertificateException e) {
+ throw new IOException("Failed to parse CA Certificate");
+ }
+ }
+
+ // Parse PKCS12 data for client private key and certificate chain.
+ byte[] pkcs12Data = mimeParts.get(TYPE_PKCS12);
+ if (pkcs12Data != null) {
+ try {
+ Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data);
+ config.credential.clientPrivateKey = clientKey.first;
+ config.credential.clientCertificateChain =
+ clientKey.second.toArray(new X509Certificate[clientKey.second.size()]);
+ } catch(GeneralSecurityException | IOException e) {
+ throw new IOException("Failed to parse PCKS12 string");
+ }
+ }
+ return config;
+ }
+
+ /**
+ * Parse a MIME (Multipurpose Internet Mail Extension) multipart message from the given
+ * input stream.
+ *
+ * @param in The input stream for reading the message data
+ * @return A map of a content type and content data pair
+ * @throws IOException
+ */
+ private static Map<String, byte[]> parseMimeMultipartMessage(LineNumberReader in)
+ throws IOException {
+ // Parse the outer MIME header.
+ MimeHeader header = parseHeaders(in);
+ if (!TextUtils.equals(header.contentType, TYPE_MULTIPART_MIXED)) {
+ throw new IOException("Invalid content type: " + header.contentType);
+ }
+ if (TextUtils.isEmpty(header.boundary)) {
+ throw new IOException("Missing boundary string");
+ }
+ if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) {
+ throw new IOException("Unexpected encoding: " + header.encodingType);
+ }
+
+ // Read pass the first boundary string.
+ for (;;) {
+ String line = in.readLine();
+ if (line == null) {
+ throw new IOException("Unexpected EOF before first boundary @ " +
+ in.getLineNumber());
+ }
+ if (line.equals("--" + header.boundary)) {
+ break;
+ }
+ }
+
+ // Parse each MIME part.
+ Map<String, byte[]> mimeParts = new HashMap<>();
+ boolean isLast = false;
+ do {
+ MimePart mimePart = parseMimePart(in, header.boundary);
+ mimeParts.put(mimePart.type, mimePart.data);
+ isLast = mimePart.isLast;
+ } while(!isLast);
+ return mimeParts;
+ }
+
+ /**
+ * Parse a MIME (Multipurpose Internet Mail Extension) part. We expect the data to
+ * be encoded in base64.
+ *
+ * @param in Input stream to read the data from
+ * @param boundary Boundary string indicate the end of the part
+ * @return {@link MimePart}
+ * @throws IOException
+ */
+ private static MimePart parseMimePart(LineNumberReader in, String boundary)
+ throws IOException {
+ MimeHeader header = parseHeaders(in);
+ // Expect encoding type to be base64.
+ if (!TextUtils.equals(header.encodingType, ENCODING_BASE64)) {
+ throw new IOException("Unexpected encoding type: " + header.encodingType);
+ }
+
+ // Check for a valid content type.
+ if (!TextUtils.equals(header.contentType, TYPE_PASSPOINT_PROFILE) &&
+ !TextUtils.equals(header.contentType, TYPE_CA_CERT) &&
+ !TextUtils.equals(header.contentType, TYPE_PKCS12)) {
+ throw new IOException("Unexpected content type: " + header.contentType);
+ }
+
+ StringBuilder text = new StringBuilder();
+ boolean isLast = false;
+ String partBoundary = "--" + boundary;
+ String endBoundary = partBoundary + "--";
+ for (;;) {
+ String line = in.readLine();
+ if (line == null) {
+ throw new IOException("Unexpected EOF file in body @ " + in.getLineNumber());
+ }
+ // Check for boundary line.
+ if (line.startsWith(partBoundary)) {
+ if (line.equals(endBoundary)) {
+ isLast = true;
+ }
+ break;
+ }
+ text.append(line);
+ }
+
+ MimePart part = new MimePart();
+ part.type = header.contentType;
+ part.data = Base64.decode(text.toString(), Base64.DEFAULT);
+ part.isLast = isLast;
+ return part;
+ }
+
+ /**
+ * Parse a MIME (Multipurpose Internet Mail Extension) header from the input stream.
+ * @param in Input stream to read from.
+ * @return {@link MimeHeader}
+ * @throws IOException
+ */
+ private static MimeHeader parseHeaders(LineNumberReader in)
+ throws IOException {
+ MimeHeader header = new MimeHeader();
+
+ // Read the header from the input stream.
+ Map<String, String> headers = readHeaders(in);
+
+ // Parse each header.
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ switch (entry.getKey()) {
+ case CONTENT_TYPE:
+ Pair<String, String> value = parseContentType(entry.getValue());
+ header.contentType = value.first;
+ header.boundary = value.second;
+ break;
+ case CONTENT_TRANSFER_ENCODING:
+ header.encodingType = entry.getValue();
+ break;
+ default:
+ throw new IOException("Unexpected header: " + entry.getKey());
+ }
+ }
+ return header;
+ }
+
+ /**
+ * Parse the Content-Type header value. The value will contain the content type string and
+ * an optional boundary string separated by a ";". Below are examples of valid Content-Type
+ * header value:
+ * multipart/mixed; boundary={boundary}
+ * application/x-passpoint-profile
+ *
+ * @param contentType The Content-Type value string
+ * @return A pair of content type and boundary string
+ * @throws IOException
+ */
+ private static Pair<String, String> parseContentType(String contentType) throws IOException {
+ String[] attributes = contentType.toString().split(";");
+ String type = null;
+ String boundary = null;
+
+ if (attributes.length < 1 || attributes.length > 2) {
+ throw new IOException("Invalid Content-Type: " + contentType);
+ }
+
+ type = attributes[0].trim();
+ if (attributes.length == 2) {
+ boundary = attributes[1].trim();
+ if (!boundary.startsWith(BOUNDARY)) {
+ throw new IOException("Invalid Content-Type: " + contentType);
+ }
+ boundary = boundary.substring(BOUNDARY.length());
+ // Remove the leading and trailing quote if present.
+ if (boundary.length() > 1 && boundary.startsWith("\"") && boundary.endsWith("\"")) {
+ boundary = boundary.substring(1, boundary.length()-1);
+ }
+ }
+
+ return new Pair<String, String>(type, boundary);
+ }
+
+ /**
+ * Read the headers from the given input stream. The header section is terminated by
+ * an empty line.
+ *
+ * @param in The input stream to read from
+ * @return Map of key-value pairs.
+ * @throws IOException
+ */
+ private static Map<String, String> readHeaders(LineNumberReader in)
+ throws IOException {
+ Map<String, String> headers = new HashMap<>();
+ String line;
+ String name = null;
+ StringBuilder value = null;
+ for (;;) {
+ line = in.readLine();
+ if (line == null) {
+ throw new IOException("Missing line @ " + in.getLineNumber());
+ }
+
+ // End of headers section.
+ if (line.length() == 0 || line.trim().length() == 0) {
+ // Save the previous header line.
+ if (name != null) {
+ headers.put(name, value.toString());
+ }
+ break;
+ }
+
+ int nameEnd = line.indexOf(':');
+ if (nameEnd < 0) {
+ if (value != null) {
+ // Continuation line for the header value.
+ value.append(' ').append(line.trim());
+ } else {
+ throw new IOException("Bad header line: '" + line + "' @ " +
+ in.getLineNumber());
+ }
+ } else {
+ // New header line detected, make sure it doesn't start with a whitespace.
+ if (Character.isWhitespace(line.charAt(0))) {
+ throw new IOException("Illegal blank prefix in header line '" + line +
+ "' @ " + in.getLineNumber());
+ }
+
+ if (name != null) {
+ // Save the previous header line.
+ headers.put(name, value.toString());
+ }
+
+ // Setup the current header line.
+ name = line.substring(0, nameEnd).trim();
+ value = new StringBuilder();
+ value.append(line.substring(nameEnd+1).trim());
+ }
+ }
+ return headers;
+ }
+
+ /**
+ * Parse a CA (Certificate Authority) certificate data and convert it to a
+ * X509Certificate object.
+ *
+ * @param octets Certificate data
+ * @return X509Certificate
+ * @throws CertificateException
+ */
+ private static X509Certificate parseCACert(byte[] octets) throws CertificateException {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(octets));
+ }
+
+ private static Pair<PrivateKey, List<X509Certificate>> parsePkcs12(byte[] octets)
+ throws GeneralSecurityException, IOException {
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ByteArrayInputStream in = new ByteArrayInputStream(octets);
+ ks.load(in, new char[0]);
+ in.close();
+
+ // Only expects one set of key and certificate chain.
+ if (ks.size() != 1) {
+ throw new IOException("Unexpected key size: " + ks.size());
+ }
+
+ String alias = ks.aliases().nextElement();
+ if (alias == null) {
+ throw new IOException("No alias found");
+ }
+
+ PrivateKey clientKey = (PrivateKey) ks.getKey(alias, null);
+ List<X509Certificate> clientCertificateChain = null;
+ Certificate[] chain = ks.getCertificateChain(alias);
+ if (chain != null) {
+ clientCertificateChain = new ArrayList<>();
+ for (Certificate certificate : chain) {
+ if (!(certificate instanceof X509Certificate)) {
+ throw new IOException("Unexpceted certificate type: " +
+ certificate.getClass());
+ }
+ clientCertificateChain.add((X509Certificate) certificate);
+ }
+ }
+ return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain);
+ }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index ee2e895..8b1cfae 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -28,5 +28,6 @@
Messenger getMessenger();
Messenger getP2pStateMachineMessenger();
void setMiracastMode(int mode);
+ void checkConfigureWifiDisplayPermission();
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 398308d..c93ac7b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1324,6 +1324,11 @@
Channel c, WifiP2pWfdInfo wfdInfo,
ActionListener listener) {
checkChannel(c);
+ try {
+ mService.checkConfigureWifiDisplayPermission();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
}
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
new file mode 100644
index 0000000..8c1eb08
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
new file mode 100644
index 0000000..6d86dd5
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -0,0 +1,73 @@
+Content-Type: multipart/mixed; boundary={boundary}
+Content-Transfer-Encoding: base64
+
+--{boundary}
+Content-Type: application/x-passpoint-profile
+Content-Transfer-Encoding: base64
+
+PE1nbXRUcmVlIHhtbG5zPSJzeW5jbWw6ZG1kZGYxLjIiPgogIDxWZXJEVEQ+MS4yPC9WZXJEVEQ+
+CiAgPE5vZGU+CiAgICA8Tm9kZU5hbWU+UGVyUHJvdmlkZXJTdWJzY3JpcHRpb248L05vZGVOYW1l
+PgogICAgPFJUUHJvcGVydGllcz4KICAgICAgPFR5cGU+CiAgICAgICAgPERERk5hbWU+dXJuOndm
+YTptbzpob3RzcG90MmRvdDAtcGVycHJvdmlkZXJzdWJzY3JpcHRpb246MS4wPC9EREZOYW1lPgog
+ICAgICA8L1R5cGU+CiAgICA8L1JUUHJvcGVydGllcz4KICAgIDxOb2RlPgogICAgICA8Tm9kZU5h
+bWU+aTAwMTwvTm9kZU5hbWU+CiAgICAgIDxOb2RlPgogICAgICAgIDxOb2RlTmFtZT5Ib21lU1A8
+L05vZGVOYW1lPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZyaWVuZGx5TmFt
+ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+Q2VudHVyeSBIb3VzZTwvVmFsdWU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZRRE48L05vZGVO
+YW1lPgogICAgICAgICAgPFZhbHVlPm1pNi5jby51azwvVmFsdWU+CiAgICAgICAgPC9Ob2RlPgog
+ICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25zb3J0aXVtT0k8L05v
+ZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVlPgogICAgICAgIDwv
+Tm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9kZU5hbWU+Q3JlZGVu
+dGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+UmVhbG08
+L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPnNoYWtlbi5zdGlycmVkLmNvbTwvVmFsdWU+CiAg
+ICAgICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlVzZXJuYW1l
+UGFzc3dvcmQ8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
+ZT5Vc2VybmFtZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5qYW1lczwvVmFsdWU+CiAg
+ICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1lPlBh
+c3N3b3JkPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPlltOXVaREF3Tnc9PTwvVmFsdWU+
+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
+PkVBUE1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
+b2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgICA8VmFsdWU+MjE8L1ZhbHVl
+PgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
+b2RlTmFtZT5Jbm5lck1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPk1TLUNI
+QVAtVjI8L1ZhbHVlPgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8L05vZGU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
+aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
+PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
+bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
+TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
+MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
+ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
+IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
+ZT4KICAgICAgICAgICAgPE5vZGVOYW1lPklNU0k8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFs
+dWU+aW1zaTwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAg
+ICAgICAgPE5vZGVOYW1lPkVBUFR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+MjQ8
+L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgog
+ICAgPC9Ob2RlPgogIDwvTm9kZT4KPC9NZ210VHJlZT4K
+
+--{boundary}
+Content-Type: application/x-x509-ca-cert
+Content-Transfer-Encoding: base64
+
+LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLRENDQWhDZ0F3SUJBZ0lKQUlMbEZkd3pM
+VnVyTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNVEIwVkJVQ0JEUVRFd0hoY05N
+VFl3TVRFeU1URTFNREUxV2hjTk1qWXdNVEE1TVRFMU1ERTFXakFTTVJBdwpEZ1lEVlFRREV3ZEZR
+VkFnUTBFeE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnpuQVBV
+ejI2TXNhZTR3czQzY3pSNDEvSjJRdHJTSVpVS21WVXNWdW1EYllIclBOdlRYS1NNWEFjZXdPUkRR
+WVgKUnF2SHZwbjhDc2NCMStvR1hadkh3eGo0elYwV0tvSzJ6ZVhrYXUzdmN5bDNISUt1cEpmcTJU
+RUFDZWZWamowdApKVytYMzVQR1dwOS9INXpJVU5WTlZqUzdVbXM4NEl2S2hSQjg1MTJQQjlVeUhh
+Z1hZVlg1R1dwQWNWcHlmcmxSCkZJOVFkaGgrUGJrMHV5a3RkYmYvQ2RmZ0hPb2ViclR0d1Jsak0w
+b0R0WCsyQ3Y2ajB3Qks3aEQ4cFB2ZjErdXkKR3pjemlnQVUvNEt3N2VacXlkZjlCKzVSdXBSK0la
+aXBYNDF4RWlJcktSd3FpNTE3V1d6WGNqYUcyY05iZjQ1MQp4cEg1UG5WM2kxdHEwNGpNR1FVekZ3
+SURBUUFCbzRHQU1INHdIUVlEVlIwT0JCWUVGSXdYNHZzOEJpQmNTY29kCjVub1pIUk04RTQraU1F
+SUdBMVVkSXdRN01EbUFGSXdYNHZzOEJpQmNTY29kNW5vWkhSTThFNCtpb1Jha0ZEQVMKTVJBd0Rn
+WURWUVFERXdkRlFWQWdRMEV4Z2drQWd1VVYzRE10VzZzd0RBWURWUjBUQkFVd0F3RUIvekFMQmdO
+VgpIUThFQkFNQ0FRWXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmZRcU9UQTdSdjdLK2x1UTdw
+bmFzNEJZd0hFCjlHRVAvdW9odjZLT3kwVEdRRmJyUlRqRm9MVk5COUJaMXltTURaMC9USXdJVWM3
+d2k3YTh0NW1FcVlIMTUzd1cKYVdvb2lTanlMTGh1STRzTnJOQ090aXNkQnEycjJNRlh0NmgwbUFR
+WU9QdjhSOEs3L2ZnU3hHRnF6aHlObW1WTAoxcUJKbGR4MzRTcHdzVEFMUVZQYjRoR3dKelpmcjFQ
+Y3BFUXg2eE1uVGw4eEVXWkUzTXM5OXVhVXhiUXFJd1J1CkxnQU9rTkNtWTJtODlWaHphSEoxdVY4
+NUFkTS90RCtZc21sbm5qdDlMUkNlamJCaXBqSUdqT1hyZzFKUCtseFYKbXVNNHZIK1AvbWxteHNQ
+UHowZDY1YitFR21KWnBvTGtPL3RkTk52Q1l6akpwVEVXcEVzTzZOTWhLWW89Ci0tLS0tRU5EIENF
+UlRJRklDQVRFLS0tLS0K
+--{boundary}--
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
new file mode 100644
index 0000000..906bfb3
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJvZmlsZQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBi
+YXNlNjQKClBFMW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lE
+eFdaWEpFVkVRK01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJX
+VStVR1Z5VUhKdmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BG
+SlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldV
+K2RYSnVPbmRtCllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNK
+cGNIUnBiMjQ2TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFK
+VVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRB
+d01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0
+WlQ1SWIyMWxVMUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
+SUNBZ1BFNXZaR1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
+SUNBZ0lDQThWbUZzZFdVK1EyVnVkSFZ5ZVNCSWIzVnpaVHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0Fn
+UEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
+a1pSUkU0OEwwNXZaR1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbTFwTmk1amJ5NTFh
+end2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2cKSUNBZ0lDQWdJRHhPYjJSbFBnb2dJ
+Q0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6YjNKMGFYVnRUMGs4TDA1dgpa
+R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFOalk4TDFaaGJI
+VmxQZ29nSUNBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBOFRt
+OWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpHVnUKZEdsaGJEd3ZUbTlrWlU1aGJX
+VStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStVbVZoYkcw
+OApMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbk5vWVd0bGJpNXpkR2x5Y21W
+a0xtTnZiVHd2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
+bFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWwKVUdGemMzZHZjbVE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJs
+VG1GdApaVDVWYzJWeWJtRnRaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
+WlQ1cVlXMWxjend2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsQmgKYzNOM2IzSmtQQzlP
+YjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGxsdE9YVmFSRUYzVG5jOVBUd3ZW
+bUZzZFdVKwpDaUFnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsClBrVkJVRTFsZEdodlpEd3ZUbTlrWlU1aGJXVStD
+aUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRa
+VDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVK01q
+RThMMVpoYkhWbApQZ29nSUNBZ0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lE
+eE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhPCmIyUmxUbUZ0WlQ1SmJtNWxjazFsZEdodlpE
+d3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGsxVExVTkkKUVZBdFZq
+SThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNB
+Z0lDQWdQRTV2WkdWT1lXMWxQa1JwWjJsMFlXeERaWEowCmFXWnBZMkYwWlR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtO
+bGNuUnBabWxqWVhSbFZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
+WlQ1NE5UQTVkak04TDFaaApiSFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0Fn
+SUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVEWlhKMFUwaEJNalUy
+Um1sdVoyVnlVSEpwYm5ROEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSsK
+TVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeApaakZtTVdZeFpqd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnCklEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBsTkpUVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFRt
+OWsKWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa2xOVTBrOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1GcwpkV1UrYVcxemFUd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lD
+QThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnCklDQWdJQ0FnUEU1dlpH
+Vk9ZVzFsUGtWQlVGUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K01qUTgKTDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05
+a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnUEM5T2IyUmxQZ29nSUR3dlRtOWtaVDRLUEM5
+TloyMTBWSEpsWlQ0SwoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC14
+NTA5LWNhLWNlcnQKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgpMUzB0TFMxQ1JV
+ZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTFJFTkRRV2hEWjBGM1NVSkJaMGxLUVVs
+TWJFWmtkM3BNClZuVnlUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOUWtsNFJVUkJUMEpuVGxZ
+S1FrRk5WRUl3VmtKVlEwSkVVVlJGZDBob1kwNU4KVkZsM1RWUkZlVTFVUlRGTlJFVXhWMmhqVGsx
+cVdYZE5WRUUxVFZSRk1VMUVSVEZYYWtGVFRWSkJkd3BFWjFsRVZsRlJSRVYzWkVaUgpWa0ZuVVRC
+RmVFMUpTVUpKYWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZGUmtGQlQwTkJVVGhCVFVsSlFrTm5TME5C
+VVVWQkNucHVRVkJWCmVqSTJUWE5oWlRSM2N6UXpZM3BTTkRFdlNqSlJkSEpUU1ZwVlMyMVdWWE5X
+ZFcxRVlsbEljbEJPZGxSWVMxTk5XRUZqWlhkUFVrUlIKV1ZnS1VuRjJTSFp3YmpoRGMyTkNNU3R2
+UjFoYWRraDNlR28wZWxZd1YwdHZTeko2WlZocllYVXpkbU41YkROSVNVdDFjRXBtY1RKVQpSVUZE
+WldaV2Ftb3dkQXBLVnl0WU16VlFSMWR3T1M5SU5YcEpWVTVXVGxacVV6ZFZiWE00TkVsMlMyaFNR
+amcxTVRKUVFqbFZlVWhoCloxaFpWbGcxUjFkd1FXTldjSGxtY214U0NrWkpPVkZrYUdnclVHSnJN
+SFY1YTNSa1ltWXZRMlJtWjBoUGIyVmljbFIwZDFKc2FrMHcKYjBSMFdDc3lRM1kyYWpCM1FrczNh
+RVE0Y0ZCMlpqRXJkWGtLUjNwamVtbG5RVlV2TkV0M04yVmFjWGxrWmpsQ0t6VlNkWEJTSzBsYQph
+WEJZTkRGNFJXbEpja3RTZDNGcE5URTNWMWQ2V0dOcVlVY3lZMDVpWmpRMU1RcDRjRWcxVUc1V00y
+a3hkSEV3TkdwTlIxRlZla1ozClNVUkJVVUZDYnpSSFFVMUlOSGRJVVZsRVZsSXdUMEpDV1VWR1NY
+ZFlOSFp6T0VKcFFtTlRZMjlrQ2pWdWIxcElVazA0UlRRcmFVMUYKU1VkQk1WVmtTWGRSTjAxRWJV
+RkdTWGRZTkhaek9FSnBRbU5UWTI5a05XNXZXa2hTVFRoRk5DdHBiMUpoYTBaRVFWTUtUVkpCZDBS
+bgpXVVJXVVZGRVJYZGtSbEZXUVdkUk1FVjRaMmRyUVdkMVZWWXpSRTEwVnpaemQwUkJXVVJXVWpC
+VVFrRlZkMEYzUlVJdmVrRk1RbWRPClZncElVVGhGUWtGTlEwRlJXWGRFVVZsS1MyOWFTV2gyWTA1
+QlVVVk1RbEZCUkdkblJVSkJSbVpSY1U5VVFUZFNkamRMSzJ4MVVUZHcKYm1Gek5FSlpkMGhGQ2ps
+SFJWQXZkVzlvZGpaTFQza3dWRWRSUm1KeVVsUnFSbTlNVms1Q09VSmFNWGx0VFVSYU1DOVVTWGRK
+VldNMwpkMmszWVRoME5XMUZjVmxJTVRVemQxY0tZVmR2YjJsVGFubE1UR2gxU1RSelRuSk9RMDkw
+YVhOa1FuRXljakpOUmxoME5tZ3diVUZSCldVOVFkamhTT0VzM0wyWm5VM2hIUm5GNmFIbE9iVzFX
+VEFveGNVSktiR1I0TXpSVGNIZHpWRUZNVVZaUVlqUm9SM2RLZWxwbWNqRlEKWTNCRlVYZzJlRTF1
+Vkd3NGVFVlhXa1V6VFhNNU9YVmhWWGhpVVhGSmQxSjFDa3huUVU5clRrTnRXVEp0T0RsV2FIcGhT
+RW94ZFZZNApOVUZrVFM5MFJDdFpjMjFzYm01cWREbE1Va05sYW1KQ2FYQnFTVWRxVDFoeVp6RktV
+Q3RzZUZZS2JYVk5OSFpJSzFBdmJXeHRlSE5RClVIb3daRFkxWWl0RlIyMUtXbkJ2VEd0UEwzUmtU
+azUyUTFsNmFrcHdWRVZYY0VWelR6Wk9UV2hMV1c4OUNpMHRMUzB0UlU1RUlFTkYKVWxSSlJrbERR
+VlJGTFMwdExTMEsKLS17Ym91bmRhcnl9LS0K
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
new file mode 100644
index 0000000..3fa97d1
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
new file mode 100644
index 0000000..975f8e5
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
@@ -0,0 +1,85 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTMyCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
+IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
+SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
+YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
+UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
+V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
+M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
+MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
+VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
+RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
+QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
+QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
+bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
+MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
+Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
+ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
+YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
+VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
+YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
+RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
+bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
+MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
+UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
+OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
+dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
+K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
+dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
+TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
+WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
+VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
+MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
+V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
+a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
+eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
+VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
+VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
+UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
+SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
+WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
+V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
+bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
+QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
+LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
+UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
+VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
+bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
+azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
+VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
+TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
+TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
+dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
+RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
+U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
+ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
+M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
+CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
+TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
+U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
+YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
+MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
+akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
+MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
+amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
+ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
+OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
+MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
+MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
+aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
+S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
+a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
+RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64
new file mode 100644
index 0000000..833c527
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithoutProfile.base64
@@ -0,0 +1,31 @@
+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
+dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
+cHBsaWNhdGlvbi94LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNl
+NjQKCkxTMHRMUzFDUlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERa
+MEYzU1VKQlowbEtRVWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5R
+a2w0UlVSQlQwSm5UbFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVS
+VEZOUkVVeFYyaGpUazFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJF
+VjNaRVpSClZrRm5VVEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVU
+aEJUVWxKUWtOblMwTkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRI
+SlRTVnBWUzIxV1ZYTldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNI
+WndiamhEYzJOQ01TdHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0
+MWNFcG1jVEpVClJVRkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpk
+VmJYTTRORWwyUzJoU1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2ta
+Sk9WRmthR2dyVUdKck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0Nz
+eVEzWTJhakIzUWtzM2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxD
+S3pWU2RYQlNLMGxhCmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalEx
+TVFwNGNFZzFVRzVXTTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxF
+VmxJd1QwSkNXVVZHU1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRC
+TVZWa1NYZFJOMDFFYlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhh
+MFpFUVZNS1RWSkJkMFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBW
+elp6ZDBSQldVUldVakJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVV
+VmxLUzI5YVNXaDJZMDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpi
+bUZ6TkVKWmQwaEZDamxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1Y
+bHRUVVJhTUM5VVNYZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRH
+aDFTVFJ6VG5KT1EwOTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUz
+aEhSbkY2YUhsT2JXMVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pG
+UQpZM0JGVVhnMmVFMXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtO
+dFdUSnRPRGxXYUhwaFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhC
+cVNVZHFUMWh5WnpGS1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIx
+S1duQnZUR3RQTDNSa1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVF
+SUVORgpVbFJKUmtsRFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
diff --git a/wifi/tests/assets/hsr1/README.txt b/wifi/tests/assets/hsr1/README.txt
new file mode 100644
index 0000000..d1f8384
--- /dev/null
+++ b/wifi/tests/assets/hsr1/README.txt
@@ -0,0 +1,5 @@
+HSR1ProfileWithCACert.conf - unencoded installation file that contains a Passpoint profile and a CA Certificate
+HSR1ProfileWithCACert.base64 - base64 encoded of the data contained in HSR1ProfileWithCAWith.conf
+HSR1ProfileWithNonBase64Part.base64 - base64 encoded installation file that contains a part of non-base64 encoding type
+HSR1ProfileWithMissingBoundary.base64 - base64 encoded installation file with missing end-boundary in the MIME data
+HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type.
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
new file mode 100644
index 0000000..6095929
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi.hotspot2;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.FakeKeys;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSP;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}.
+ */
+@SmallTest
+public class ConfigBuilderTest {
+ /**
+ * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a
+ * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}.
+ */
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT =
+ "assets/hsr1/HSR1ProfileWithCACert.base64";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA =
+ "assets/hsr1/HSR1ProfileWithCACert.conf";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART =
+ "assets/hsr1/HSR1ProfileWithNonBase64Part.base64";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY =
+ "assets/hsr1/HSR1ProfileWithMissingBoundary.base64";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE =
+ "assets/hsr1/HSR1ProfileWithInvalidContentType.base64";
+ private static final String PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE =
+ "assets/hsr1/HSR1ProfileWithoutProfile.base64";
+
+ /**
+ * Read the content of the given resource file into a String.
+ *
+ * @param filename String name of the file
+ * @return String
+ * @throws IOException
+ */
+ private String loadResourceFile(String filename) throws IOException {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line).append("\n");
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
+ * XML file {@link #PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT}.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ private PasspointConfiguration generateConfigurationFromProfile() {
+ PasspointConfiguration config = new PasspointConfiguration();
+
+ // HomeSP configuration.
+ config.homeSp = new HomeSP();
+ config.homeSp.friendlyName = "Century House";
+ config.homeSp.fqdn = "mi6.co.uk";
+ config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+
+ // Credential configuration.
+ config.credential = new Credential();
+ config.credential.realm = "shaken.stirred.com";
+ config.credential.userCredential = new Credential.UserCredential();
+ config.credential.userCredential.username = "james";
+ config.credential.userCredential.password = "Ym9uZDAwNw==";
+ config.credential.userCredential.eapType = 21;
+ config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
+ config.credential.certCredential = new Credential.CertificateCredential();
+ config.credential.certCredential.certType = "x509v3";
+ config.credential.certCredential.certSha256FingerPrint = new byte[32];
+ Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
+ config.credential.simCredential = new Credential.SimCredential();
+ config.credential.simCredential.imsi = "imsi";
+ config.credential.simCredential.eapType = 24;
+ config.credential.caCertificate = FakeKeys.CA_CERT0;
+ return config;
+ }
+
+ /**
+ * Verify a valid installation file is parsed successfully with the matching contents.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFile() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
+ PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
+ PasspointConfiguration actualConfig =
+ ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes());
+ assertTrue(actualConfig.equals(expectedConfig));
+ }
+
+ /**
+ * Verify that parsing an installation file with invalid MIME type will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithInvalidMimeType() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/wifi-config", configStr.getBytes()));
+ }
+
+ /**
+ * Verify that parsing an un-encoded installation file will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithUnencodedData() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes()));
+ }
+
+ /**
+ * Verify that parsing an installation file that contains a non-base64 part will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithInvalidPart() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes()));
+ }
+
+ /**
+ * Verify that parsing an installation file that contains a missing boundary string will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithMissingBoundary() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes()));
+ }
+
+ /**
+ * Verify that parsing an installation file that contains a MIME part with an invalid content
+ * type will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithInvalidContentType() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes()));
+ }
+
+ /**
+ * Verify that parsing an installation file that doesn't contain a Passpoint profile will fail.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseConfigFileWithoutPasspointProfile() throws Exception {
+ String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE);
+ assertNull(ConfigBuilder.buildPasspointConfig(
+ "application/x-wifi-config", configStr.getBytes()));
+ }
+}
\ No newline at end of file