diff options
118 files changed, 3687 insertions, 1920 deletions
diff --git a/Android.bp b/Android.bp index 47ad24a01924..faad6f32dec4 100644 --- a/Android.bp +++ b/Android.bp @@ -77,6 +77,7 @@ java_defaults { "core/java/android/app/ISearchManager.aidl", "core/java/android/app/ISearchManagerCallback.aidl", "core/java/android/app/IServiceConnection.aidl", + "core/java/android/app/ISmsAppService.aidl", "core/java/android/app/IStopUserCallback.aidl", "core/java/android/app/job/IJobCallback.aidl", "core/java/android/app/job/IJobScheduler.aidl", @@ -706,7 +707,6 @@ java_defaults { // Loaded with System.loadLibrary by android.view.textclassifier required: [ - "libtextclassifier", "libmedia2_jni", ], @@ -816,6 +816,10 @@ java_library { "nist-sip", "tagsoup", "rappor", + "libtextclassifier-java", + ], + required: [ + "libtextclassifier", ], dxflags: ["--core-library"], } diff --git a/api/current.txt b/api/current.txt index 52257c0f7529..90a0f6550fc5 100755 --- a/api/current.txt +++ b/api/current.txt @@ -37,6 +37,7 @@ package android { field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE"; field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS"; field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE"; + field public static final java.lang.String BIND_SMS_APP_SERVICE = "android.permission.BIND_SMS_APP_SERVICE"; field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE"; field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE"; field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT"; @@ -4296,6 +4297,20 @@ package android.app { method public abstract void onActivityCreated(android.app.Activity, android.os.Bundle); method public abstract void onActivityDestroyed(android.app.Activity); method public abstract void onActivityPaused(android.app.Activity); + method public default void onActivityPostCreated(android.app.Activity, android.os.Bundle); + method public default void onActivityPostDestroyed(android.app.Activity); + method public default void onActivityPostPaused(android.app.Activity); + method public default void onActivityPostResumed(android.app.Activity); + method public default void onActivityPostSaveInstanceState(android.app.Activity, android.os.Bundle); + method public default void onActivityPostStarted(android.app.Activity); + method public default void onActivityPostStopped(android.app.Activity); + method public default void onActivityPreCreated(android.app.Activity, android.os.Bundle); + method public default void onActivityPreDestroyed(android.app.Activity); + method public default void onActivityPrePaused(android.app.Activity); + method public default void onActivityPreResumed(android.app.Activity); + method public default void onActivityPreSaveInstanceState(android.app.Activity, android.os.Bundle); + method public default void onActivityPreStarted(android.app.Activity); + method public default void onActivityPreStopped(android.app.Activity); method public abstract void onActivityResumed(android.app.Activity); method public abstract void onActivitySaveInstanceState(android.app.Activity, android.os.Bundle); method public abstract void onActivityStarted(android.app.Activity); @@ -6095,6 +6110,11 @@ package android.app { method public abstract void onSharedElementsReady(); } + public class SmsAppService extends android.app.Service { + ctor public SmsAppService(); + method public final android.os.IBinder onBind(android.content.Intent); + } + public deprecated class TabActivity extends android.app.ActivityGroup { ctor public TabActivity(); method public android.widget.TabHost getTabHost(); @@ -42920,6 +42940,7 @@ package android.telephony { method public static int getSlotIndex(int); method public static int[] getSubscriptionIds(int); method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); + method public boolean isActiveSubscriptionId(int); method public boolean isNetworkRoaming(int); method public static boolean isValidSubscriptionId(int); method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); @@ -43072,6 +43093,7 @@ package android.telephony { field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; field public static final java.lang.String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE"; field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION"; + field public static final java.lang.String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE"; field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED"; field public static final int APPTYPE_CSIM = 4; // 0x4 field public static final int APPTYPE_ISIM = 5; // 0x5 @@ -51407,7 +51429,7 @@ package android.webkit { } public abstract class CookieManager { - ctor public CookieManager(); + ctor public deprecated CookieManager(); method public abstract boolean acceptCookie(); method public abstract boolean acceptThirdPartyCookies(android.webkit.WebView); method public static boolean allowFileSchemeCookies(); @@ -51507,13 +51529,13 @@ package android.webkit { } public abstract class RenderProcessGoneDetail { - ctor public RenderProcessGoneDetail(); + ctor public deprecated RenderProcessGoneDetail(); method public abstract boolean didCrash(); method public abstract int rendererPriorityAtExit(); } public abstract class SafeBrowsingResponse { - ctor public SafeBrowsingResponse(); + ctor public deprecated SafeBrowsingResponse(); method public abstract void backToSafety(boolean); method public abstract void proceed(boolean); method public abstract void showInterstitial(boolean); @@ -51525,7 +51547,7 @@ package android.webkit { } public abstract class ServiceWorkerController { - ctor public ServiceWorkerController(); + ctor public deprecated ServiceWorkerController(); method public static android.webkit.ServiceWorkerController getInstance(); method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings(); method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient); @@ -51574,7 +51596,7 @@ package android.webkit { } public abstract class TracingController { - ctor public TracingController(); + ctor public deprecated TracingController(); method public static android.webkit.TracingController getInstance(); method public abstract boolean isTracing(); method public abstract void start(android.webkit.TracingConfig); @@ -52114,7 +52136,7 @@ package android.webkit { } public abstract class WebViewDatabase { - ctor public WebViewDatabase(); + ctor public deprecated WebViewDatabase(); method public abstract deprecated void clearFormData(); method public abstract void clearHttpAuthUsernamePassword(); method public abstract deprecated void clearUsernamePassword(); diff --git a/api/system-current.txt b/api/system-current.txt index 1f74cbf6312c..5785e4aa3969 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5439,6 +5439,7 @@ package android.telephony { method public boolean disableDataConnectivity(); method public boolean enableDataConnectivity(); method public void enableVideoCalling(boolean); + method public java.lang.String getAidForAppType(int); method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); @@ -5454,6 +5455,7 @@ package android.telephony { method public deprecated boolean getDataEnabled(int); method public boolean getEmergencyCallbackMode(); method public java.lang.String getIsimDomain(); + method public int getPreferredNetworkType(int); method public int getSimApplicationState(); method public int getSimCardState(); method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); @@ -5463,10 +5465,7 @@ package android.telephony { method public boolean handlePinMmi(java.lang.String); method public boolean handlePinMmiForSubscriber(int, java.lang.String); method public boolean isDataConnectivityPossible(); - method public deprecated boolean isIdle(); - method public deprecated boolean isOffhook(); method public deprecated boolean isRadioOn(); - method public deprecated boolean isRinging(); method public boolean isVideoCallingEnabled(); method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); method public boolean needsOtaServiceProvisioning(); @@ -5480,7 +5479,6 @@ package android.telephony { method public void setSimPowerStateForSlot(int, int); method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean); method public void setVoiceActivationState(int); - method public deprecated void silenceRinger(); method public boolean supplyPin(java.lang.String); method public int[] supplyPinReportResult(java.lang.String); method public boolean supplyPuk(java.lang.String, java.lang.String); @@ -5498,6 +5496,29 @@ package android.telephony { field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; + field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4 + field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5 + field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6 + field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7 + field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1 + field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3 + field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8 + field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa + field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9 + field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb + field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf + field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16 + field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11 + field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14 + field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13 + field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc + field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15 + field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10 + field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12 + field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd + field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe + field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2 + field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0 field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2 field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1 field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3 diff --git a/api/system-removed.txt b/api/system-removed.txt index 9012c3315cfe..22465621e693 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -148,6 +148,10 @@ package android.telephony { public class TelephonyManager { method public deprecated void answerRingingCall(); method public deprecated boolean endCall(); + method public deprecated boolean isIdle(); + method public deprecated boolean isOffhook(); + method public deprecated boolean isRinging(); + method public deprecated void silenceRinger(); } } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 448608e9ece7..1e9c354d26bf 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -80,7 +80,8 @@ message Atom { BatteryLevelChanged battery_level_changed = 30; ChargingStateChanged charging_state_changed = 31; PluggedStateChanged plugged_state_changed = 32; - // 33 - 34 are available + InteractiveStateChanged interactive_state_changed = 33; + // 34 is available WakeupAlarmOccurred wakeup_alarm_occurred = 35; KernelWakeupReported kernel_wakeup_reported = 36; WifiLockStateChanged wifi_lock_state_changed = 37; @@ -665,6 +666,20 @@ message LongPartialWakelockStateChanged { } /** + * Logs when the device is interactive, according to the PowerManager Notifier. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/power/Notifier.java + */ +message InteractiveStateChanged { + enum State { + OFF = 0; + ON = 1; + } + optional State state = 1; +} + +/** * Logs Battery Saver state change. * * Logged from: diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 04724616420b..ac16fd311c32 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -2076,27 +2076,20 @@ Lcom/android/internal/telephony/ISub;->getDefaultDataSubId()I Lcom/android/internal/telephony/ISub;->getDefaultSubId()I Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCallForSubscriber(I)Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String; Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder; Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony; Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String; -Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_answerRingingCall:I Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I -Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_endCall:I Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I -Lcom/android/internal/telephony/ITelephony;->answerRingingCall()V Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->disableLocationUpdates()V Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V -Lcom/android/internal/telephony/ITelephony;->endCall()Z -Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I Lcom/android/internal/telephony/ITelephony;->getCallState()I Lcom/android/internal/telephony/ITelephony;->getDataActivity()I @@ -2108,12 +2101,8 @@ Lcom/android/internal/telephony/ITelephony;->handlePinMmiForSubscriber(ILjava/la Lcom/android/internal/telephony/ITelephony;->hasIccCard()Z Lcom/android/internal/telephony/ITelephony;->iccCloseLogicalChannel(II)Z Lcom/android/internal/telephony/ITelephony;->iccTransmitApduLogicalChannel(IIIIIIILjava/lang/String;)Ljava/lang/String; -Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z -Lcom/android/internal/telephony/ITelephony;->isIdleForSubscriber(ILjava/lang/String;)Z Lcom/android/internal/telephony/ITelephony;->isRadioOnForSubscriber(ILjava/lang/String;)Z -Lcom/android/internal/telephony/ITelephony;->isRinging(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z -Lcom/android/internal/telephony/ITelephony;->silenceRinger()V Lcom/android/internal/telephony/ITelephony;->supplyPin(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony;->toggleRadioOnOff()V Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2ee266de4c77..2acae1cf8bac 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1588,11 +1588,13 @@ public class Activity extends ContextThemeWrapper * @param outState The bundle to save the state to. */ final void performSaveInstanceState(@NonNull Bundle outState) { + getApplication().dispatchActivityPreSaveInstanceState(this, outState); onSaveInstanceState(outState); saveManagedDialogs(outState); mActivityTransitionState.saveState(outState); storeHasCurrentPermissionRequest(outState); if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState); + getApplication().dispatchActivityPostSaveInstanceState(this, outState); } /** @@ -1606,11 +1608,13 @@ public class Activity extends ContextThemeWrapper */ final void performSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) { + getApplication().dispatchActivityPreSaveInstanceState(this, outState); onSaveInstanceState(outState, outPersistentState); saveManagedDialogs(outState); storeHasCurrentPermissionRequest(outState); if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState + ", " + outPersistentState); + getApplication().dispatchActivityPostSaveInstanceState(this, outState); } /** @@ -7195,6 +7199,7 @@ public class Activity extends ContextThemeWrapper @UnsupportedAppUsage final void performCreate(Bundle icicle, PersistableBundle persistentState) { + getApplication().dispatchActivityPreCreated(this, icicle); mCanEnterPictureInPicture = true; restoreHasCurrentPermissionRequest(icicle); if (persistentState != null) { @@ -7209,6 +7214,7 @@ public class Activity extends ContextThemeWrapper com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); + getApplication().dispatchActivityPostCreated(this, icicle); } final void performNewIntent(@NonNull Intent intent) { @@ -7217,6 +7223,7 @@ public class Activity extends ContextThemeWrapper } final void performStart(String reason) { + getApplication().dispatchActivityPreStarted(this); mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); mFragments.noteStateNotSaved(); mCalled = false; @@ -7284,6 +7291,7 @@ public class Activity extends ContextThemeWrapper } mActivityTransitionState.enterReady(this); + getApplication().dispatchActivityPostStarted(this); } /** @@ -7338,6 +7346,7 @@ public class Activity extends ContextThemeWrapper } final void performResume(boolean followedByPause, String reason) { + getApplication().dispatchActivityPreResumed(this); performRestart(true /* start */, reason); mFragments.execPendingActions(); @@ -7387,9 +7396,11 @@ public class Activity extends ContextThemeWrapper "Activity " + mComponent.toShortString() + " did not call through to super.onPostResume()"); } + getApplication().dispatchActivityPostResumed(this); } final void performPause() { + getApplication().dispatchActivityPrePaused(this); mDoReportFullyDrawn = false; mFragments.dispatchPause(); mCalled = false; @@ -7402,6 +7413,7 @@ public class Activity extends ContextThemeWrapper "Activity " + mComponent.toShortString() + " did not call through to super.onPause()"); } + getApplication().dispatchActivityPostPaused(this); } final void performUserLeaving() { @@ -7417,6 +7429,7 @@ public class Activity extends ContextThemeWrapper mCanEnterPictureInPicture = false; if (!mStopped) { + getApplication().dispatchActivityPreStopped(this); if (mWindow != null) { mWindow.closeAllPanels(); } @@ -7451,11 +7464,13 @@ public class Activity extends ContextThemeWrapper } mStopped = true; + getApplication().dispatchActivityPostStopped(this); } mResumed = false; } final void performDestroy() { + getApplication().dispatchActivityPreDestroyed(this); mDestroyed = true; mWindow.destroy(); mFragments.dispatchDestroy(); @@ -7465,6 +7480,7 @@ public class Activity extends ContextThemeWrapper if (mVoiceInteractor != null) { mVoiceInteractor.detachActivity(); } + getApplication().dispatchActivityPostDestroyed(this); } final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index be1f2dbc8e4f..294a3ec73efd 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -19,11 +19,14 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; +import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.UserInfo; +import android.os.Bundle; import android.os.IBinder; +import android.os.TransactionTooLargeException; import android.view.RemoteAnimationAdapter; import java.util.ArrayList; @@ -232,4 +235,14 @@ public abstract class ActivityManagerInternal { public abstract void setBooted(boolean booted); public abstract boolean isBooted(); public abstract void finishBooting(); + + public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, + long duration, String tag); + public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent, + String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, + Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, + boolean sticky, int userId); + public abstract ComponentName startServiceInPackage(int uid, Intent service, + String resolvedType, boolean fgRequired, String callingPackage, int userId) + throws TransactionTooLargeException; } diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 68b745d54bc0..e12942f248d4 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -65,13 +65,144 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { public LoadedApk mLoadedApk; public interface ActivityLifecycleCallbacks { + + /** + * Called as the first step of the Activity being created. This is always called before + * {@link Activity#onCreate}. + */ + default void onActivityPreCreated(@NonNull Activity activity, + @Nullable Bundle savedInstanceState) { + } + + /** + * Called when the Activity calls {@link Activity#onCreate super.onCreate()}. + */ void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState); + + /** + * Called as the last step of the Activity being created. This is always called after + * {@link Activity#onCreate}. + */ + default void onActivityPostCreated(@NonNull Activity activity, + @Nullable Bundle savedInstanceState) { + } + + /** + * Called as the first step of the Activity being started. This is always called before + * {@link Activity#onStart}. + */ + default void onActivityPreStarted(@NonNull Activity activity) { + } + + /** + * Called when the Activity calls {@link Activity#onStart super.onStart()}. + */ void onActivityStarted(@NonNull Activity activity); + + /** + * Called as the last step of the Activity being started. This is always called after + * {@link Activity#onStart}. + */ + default void onActivityPostStarted(@NonNull Activity activity) { + } + + /** + * Called as the first step of the Activity being resumed. This is always called before + * {@link Activity#onResume}. + */ + default void onActivityPreResumed(@NonNull Activity activity) { + } + + /** + * Called when the Activity calls {@link Activity#onResume super.onResume()}. + */ void onActivityResumed(@NonNull Activity activity); + + /** + * Called as the last step of the Activity being resumed. This is always called after + * {@link Activity#onResume} and {@link Activity#onPostResume}. + */ + default void onActivityPostResumed(@NonNull Activity activity) { + } + + /** + * Called as the first step of the Activity being paused. This is always called before + * {@link Activity#onPause}. + */ + default void onActivityPrePaused(@NonNull Activity activity) { + } + + /** + * Called when the Activity calls {@link Activity#onPause super.onPause()}. + */ void onActivityPaused(@NonNull Activity activity); + + /** + * Called as the last step of the Activity being paused. This is always called after + * {@link Activity#onPause}. + */ + default void onActivityPostPaused(@NonNull Activity activity) { + } + + /** + * Called as the first step of the Activity being stopped. This is always called before + * {@link Activity#onStop}. + */ + default void onActivityPreStopped(@NonNull Activity activity) { + } + + /** + * Called when the Activity calls {@link Activity#onStop super.onStop()}. + */ void onActivityStopped(@NonNull Activity activity); + + /** + * Called as the last step of the Activity being stopped. This is always called after + * {@link Activity#onStop}. + */ + default void onActivityPostStopped(@NonNull Activity activity) { + } + + /** + * Called as the first step of the Activity saving its instance state. This is always + * called before {@link Activity#onSaveInstanceState}. + */ + default void onActivityPreSaveInstanceState(@NonNull Activity activity, + @NonNull Bundle outState) { + } + + /** + * Called when the Activity calls + * {@link Activity#onSaveInstanceState super.onSaveInstanceState()}. + */ void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState); + + /** + * Called as the last step of the Activity saving its instance state. This is always + * called after{@link Activity#onSaveInstanceState}. + */ + default void onActivityPostSaveInstanceState(@NonNull Activity activity, + @NonNull Bundle outState) { + } + + /** + * Called as the first step of the Activity being destroyed. This is always called before + * {@link Activity#onDestroy}. + */ + default void onActivityPreDestroyed(@NonNull Activity activity) { + } + + /** + * Called when the Activity calls {@link Activity#onDestroy super.onDestroy()}. + */ void onActivityDestroyed(@NonNull Activity activity); + + /** + * Called as the last step of the Activity being destroyed. This is always called after + * {@link Activity#onDestroy}. + */ + default void onActivityPostDestroyed(@NonNull Activity activity) { + } } /** @@ -222,6 +353,18 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPreCreated(@NonNull Activity activity, + @Nullable Bundle savedInstanceState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreCreated(activity, + savedInstanceState); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) { Object[] callbacks = collectActivityLifecycleCallbacks(); @@ -234,6 +377,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostCreated(@NonNull Activity activity, + @Nullable Bundle savedInstanceState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(activity, + savedInstanceState); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPreStarted(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStarted(activity); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityStarted(@NonNull Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { @@ -244,6 +409,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostStarted(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStarted(activity); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPreResumed(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreResumed(activity); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityResumed(@NonNull Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { @@ -254,6 +439,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostResumed(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostResumed(activity); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPrePaused(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPrePaused(activity); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityPaused(@NonNull Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { @@ -264,6 +469,26 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostPaused(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostPaused(activity); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPreStopped(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStopped(activity); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityStopped(@NonNull Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { @@ -274,6 +499,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostStopped(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostStopped(activity); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPreSaveInstanceState(@NonNull Activity activity, + @NonNull Bundle outState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreSaveInstanceState( + activity, outState); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) { Object[] callbacks = collectActivityLifecycleCallbacks(); @@ -286,6 +533,28 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } @UnsupportedAppUsage + /* package */ void dispatchActivityPostSaveInstanceState(@NonNull Activity activity, + @NonNull Bundle outState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostSaveInstanceState( + activity, outState); + } + } + } + + @UnsupportedAppUsage + /* package */ void dispatchActivityPreDestroyed(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPreDestroyed(activity); + } + } + } + + @UnsupportedAppUsage /* package */ void dispatchActivityDestroyed(@NonNull Activity activity) { Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { @@ -295,6 +564,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } } + @UnsupportedAppUsage + /* package */ void dispatchActivityPostDestroyed(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityPostDestroyed(activity); + } + } + } + private Object[] collectComponentCallbacks() { Object[] callbacks = null; synchronized (mComponentCallbacks) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/core/java/android/app/ISmsAppService.aidl index c50d6d62d6e9..1ac2ec6b1c41 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java +++ b/core/java/android/app/ISmsAppService.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,15 +11,13 @@ * 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. */ -package com.android.systemui.stackdivider.events; - -import com.android.systemui.recents.events.EventBus; +package android.app; /** - * Sent when the divider isn't draging anymore. + * @hide */ -public class StoppedDragingEvent extends EventBus.Event { +interface ISmsAppService { } diff --git a/core/java/android/app/SmsAppService.java b/core/java/android/app/SmsAppService.java new file mode 100644 index 000000000000..3f2b025016df --- /dev/null +++ b/core/java/android/app/SmsAppService.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.app; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.IBinder; + +/** + * If the default SMS app has a service that extends this class, the system always tries to bind + * it so that the process is always running, which allows the app to have a persistent connection + * to the server. + * + * <p>The service must have {@link android.telephony.TelephonyManager#ACTION_SMS_APP_SERVICE} + * action in the intent handler, and be protected with + * {@link android.Manifest.permission#BIND_SMS_APP_SERVICE}. However the service does not have to + * be exported. + * + * <p>Apps can use + * {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)} + * to disable/enable the service. Apps should use it to disable the service when it no longer needs + * to be running. + * + * <p>When the owner process crashes, the service will be re-bound automatically after a + * back-off. + * + * <p>Note the process may still be killed if the system is under heavy memory pressure, in which + * case the process will be re-started later. + */ +public class SmsAppService extends Service { + private final ISmsAppService mImpl; + + public SmsAppService() { + mImpl = new ISmsAppServiceImpl(); + } + + @Override + public final IBinder onBind(Intent intent) { + return mImpl.asBinder(); + } + + private class ISmsAppServiceImpl extends ISmsAppService.Stub { + } +} diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 8d9533e09cbf..a64eead04c6f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -331,6 +331,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (int i = 0; i < numOperations; i++) { ContentProviderOperation operation = operations.get(i); Uri uri = operation.getUri(); + userIds[i] = getUserIdFromUri(uri); uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); // Rebuild operation if we changed the Uri above diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index caaf4af247e9..d71157459fc8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4311,6 +4311,12 @@ public abstract class Context { public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector"; /** + * Binder service name for {@link AppBindingService}. + * @hide + */ + public static final String APP_BINDING_SERVICE = "app_binding"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index f8e8762ef592..c4ef77a3e7ae 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -189,6 +189,8 @@ public class TransitionManager { final ViewGroup sceneRoot = scene.getSceneRoot(); if (!sPendingTransitions.contains(sceneRoot)) { if (transition == null) { + exitPreviousScene(sceneRoot); + scene.enter(); } else { sPendingTransitions.add(sceneRoot); @@ -210,6 +212,14 @@ public class TransitionManager { } } + private static void exitPreviousScene(final ViewGroup sceneRoot) { + // Notify previous scene that it is being exited + final Scene previousScene = Scene.getCurrentScene(sceneRoot); + if (previousScene != null) { + previousScene.exit(); + } + } + @UnsupportedAppUsage private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() { WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions = @@ -339,11 +349,7 @@ public class TransitionManager { transition.captureValues(sceneRoot, true); } - // Notify previous scene that it is being exited - Scene previousScene = Scene.getCurrentScene(sceneRoot); - if (previousScene != null) { - previousScene.exit(); - } + exitPreviousScene(sceneRoot); } /** diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java index 553511d73670..edd09f8f73c4 100644 --- a/core/java/android/util/apk/ApkVerityBuilder.java +++ b/core/java/android/util/apk/ApkVerityBuilder.java @@ -40,7 +40,7 @@ import java.util.ArrayList; * * @hide */ -abstract class ApkVerityBuilder { +public abstract class ApkVerityBuilder { private ApkVerityBuilder() {} private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size @@ -51,12 +51,18 @@ abstract class ApkVerityBuilder { private static final String JCA_DIGEST_ALGORITHM = "SHA-256"; private static final byte[] DEFAULT_SALT = new byte[8]; - static class ApkVerityResult { + /** Result generated by the builder. */ + public static class ApkVerityResult { + /** Raw fs-verity metadata and Merkle tree ready to be deployed on disk. */ public final ByteBuffer verityData; + + /** Size of the Merkle tree in {@code verityData}. */ public final int merkleTreeSize; + + /** Root hash of the Merkle tree. */ public final byte[] rootHash; - ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) { + private ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) { this.verityData = verityData; this.merkleTreeSize = merkleTreeSize; this.rootHash = rootHash; @@ -65,19 +71,47 @@ abstract class ApkVerityBuilder { /** * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link - * ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree is suitable to be used - * as the on-disk format for apk-verity. + * ByteBuffer} created by the {@link ByteBufferFactory}. The output is suitable to be used as + * the on-disk format for fs-verity to use. * * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the * front, the tree size, and the calculated root hash. */ @NonNull - static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk, + public static ApkVerityResult generateFsVerityTree(@NonNull RandomAccessFile apk, + @NonNull ByteBufferFactory bufferFactory) + throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { + return generateVerityTree(apk, bufferFactory, null /* signatureInfo */, + false /* skipSigningBlock */); + } + + /** + * Generates the 4k, SHA-256 based Merkle tree for the given APK and stores in the {@link + * ByteBuffer} created by the {@link ByteBufferFactory}. The Merkle tree does not cover Signing + * Block specificed in {@code signatureInfo}. The output is suitable to be used as the on-disk + * format for fs-verity to use (with elide and patch extensions). + * + * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the + * front, the tree size, and the calculated root hash. + */ + @NonNull + public static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk, @Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory) throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { - long signingBlockSize = - signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; - long dataSize = apk.length() - signingBlockSize; + return generateVerityTree(apk, bufferFactory, signatureInfo, true /* skipSigningBlock */); + } + + @NonNull + private static ApkVerityResult generateVerityTree(@NonNull RandomAccessFile apk, + @NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo, + boolean skipSigningBlock) + throws IOException, SecurityException, NoSuchAlgorithmException, DigestException { + long dataSize = apk.length(); + if (skipSigningBlock) { + long signingBlockSize = + signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; + dataSize -= signingBlockSize; + } int[] levelOffset = calculateVerityLevelOffset(dataSize); int merkleTreeSize = levelOffset[levelOffset.length - 1]; @@ -85,10 +119,11 @@ abstract class ApkVerityBuilder { merkleTreeSize + CHUNK_SIZE_BYTES); // maximum size of apk-verity metadata output.order(ByteOrder.LITTLE_ENDIAN); - ByteBuffer tree = slice(output, 0, merkleTreeSize); - byte[] apkRootHash = generateApkVerityTreeInternal(apk, signatureInfo, DEFAULT_SALT, - levelOffset, tree); + // Only use default salt in legacy case. + byte[] salt = skipSigningBlock ? DEFAULT_SALT : null; + byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset, + tree, skipSigningBlock); return new ApkVerityResult(output, merkleTreeSize, apkRootHash); } @@ -138,7 +173,8 @@ abstract class ApkVerityBuilder { throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { - ApkVerityResult result = generateApkVerityTree(apk, signatureInfo, bufferFactory); + ApkVerityResult result = generateVerityTree(apk, bufferFactory, signatureInfo, + true /* skipSigningBlock */); ByteBuffer footer = slice(result.verityData, result.merkleTreeSize, result.verityData.limit()); generateApkVerityFooter(apk, signatureInfo, footer); @@ -170,11 +206,14 @@ abstract class ApkVerityBuilder { private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES]; private final byte[] mSalt; - private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException { + private BufferedDigester(@Nullable byte[] salt, @NonNull ByteBuffer output) + throws NoSuchAlgorithmException { mSalt = salt; mOutput = output.slice(); mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM); - mMd.update(mSalt); + if (mSalt != null) { + mMd.update(mSalt); + } mBytesDigestedSinceReset = 0; } @@ -201,7 +240,9 @@ abstract class ApkVerityBuilder { mMd.digest(mDigestBuffer, 0, mDigestBuffer.length); mOutput.put(mDigestBuffer); // After digest, MessageDigest resets automatically, so no need to reset again. - mMd.update(mSalt); + if (mSalt != null) { + mMd.update(mSalt); + } mBytesDigestedSinceReset = 0; } } @@ -242,6 +283,26 @@ abstract class ApkVerityBuilder { // thus the syscall overhead is not too big. private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024; + private static void generateFsVerityDigestAtLeafLevel(RandomAccessFile file, ByteBuffer output) + throws IOException, NoSuchAlgorithmException, DigestException { + BufferedDigester digester = new BufferedDigester(null /* salt */, output); + + // 1. Digest the whole file by chunks. + consumeByChunk(digester, + new MemoryMappedFileDataSource(file.getFD(), 0, file.length()), + MMAP_REGION_SIZE_BYTES); + + // 2. Pad 0s up to the nearest 4096-byte block before hashing. + int lastIncompleteChunkSize = (int) (file.length() % CHUNK_SIZE_BYTES); + if (lastIncompleteChunkSize != 0) { + digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize)); + } + digester.assertEmptyBuffer(); + + // 3. Fill up the rest of buffer with 0s. + digester.fillUpLastOutputChunk(); + } + private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk, SignatureInfo signatureInfo, byte[] salt, ByteBuffer output) throws IOException, NoSuchAlgorithmException, DigestException { @@ -288,15 +349,19 @@ abstract class ApkVerityBuilder { } @NonNull - private static byte[] generateApkVerityTreeInternal(@NonNull RandomAccessFile apk, - @Nullable SignatureInfo signatureInfo, @NonNull byte[] salt, - @NonNull int[] levelOffset, @NonNull ByteBuffer output) + private static byte[] generateVerityTreeInternal(@NonNull RandomAccessFile apk, + @Nullable SignatureInfo signatureInfo, @Nullable byte[] salt, + @NonNull int[] levelOffset, @NonNull ByteBuffer output, boolean skipSigningBlock) throws IOException, NoSuchAlgorithmException, DigestException { - assertSigningBlockAlignedAndHasFullPages(signatureInfo); - // 1. Digest the apk to generate the leaf level hashes. - generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output, - levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); + if (skipSigningBlock) { + assertSigningBlockAlignedAndHasFullPages(signatureInfo); + generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output, + levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); + } else { + generateFsVerityDigestAtLeafLevel(apk, slice(output, + levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); + } // 2. Digest the lower level hashes bottom up. for (int level = levelOffset.length - 3; level >= 0; level--) { @@ -434,10 +499,11 @@ abstract class ApkVerityBuilder { return levelOffset; } - private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) { + private static void assertSigningBlockAlignedAndHasFullPages( + @NonNull SignatureInfo signatureInfo) { if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) { throw new IllegalArgumentException( - "APK Signing Block does not start at the page boundary: " + "APK Signing Block does not start at the page boundary: " + signatureInfo.apkSigningBlockOffset); } diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 29339e915ce0..3e240cfdb69f 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.google.android.textclassifier.AnnotatorModel; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -92,7 +94,7 @@ public final class TextClassifierImpl implements TextClassifier { @GuardedBy("mLock") // Do not access outside this lock. private ModelFile mModel; @GuardedBy("mLock") // Do not access outside this lock. - private TextClassifierImplNative mNative; + private AnnotatorModel mNative; private final Object mLoggerLock = new Object(); @GuardedBy("mLoggerLock") // Do not access outside this lock. @@ -125,7 +127,7 @@ public final class TextClassifierImpl implements TextClassifier { && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) { final String localesString = concatenateLocales(request.getDefaultLocales()); final ZonedDateTime refTime = ZonedDateTime.now(); - final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales()); + final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales()); final int start; final int end; if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) { @@ -134,7 +136,7 @@ public final class TextClassifierImpl implements TextClassifier { } else { final int[] startEnd = nativeImpl.suggestSelection( string, request.getStartIndex(), request.getEndIndex(), - new TextClassifierImplNative.SelectionOptions(localesString)); + new AnnotatorModel.SelectionOptions(localesString)); start = startEnd[0]; end = startEnd[1]; } @@ -142,10 +144,10 @@ public final class TextClassifierImpl implements TextClassifier { && start >= 0 && end <= string.length() && start <= request.getStartIndex() && end >= request.getEndIndex()) { final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end); - final TextClassifierImplNative.ClassificationResult[] results = + final AnnotatorModel.ClassificationResult[] results = nativeImpl.classifyText( string, start, end, - new TextClassifierImplNative.ClassificationOptions( + new AnnotatorModel.ClassificationOptions( refTime.toInstant().toEpochMilli(), refTime.getZone().getId(), localesString)); @@ -184,11 +186,11 @@ public final class TextClassifierImpl implements TextClassifier { final String localesString = concatenateLocales(request.getDefaultLocales()); final ZonedDateTime refTime = request.getReferenceTime() != null ? request.getReferenceTime() : ZonedDateTime.now(); - final TextClassifierImplNative.ClassificationResult[] results = + final AnnotatorModel.ClassificationResult[] results = getNative(request.getDefaultLocales()) .classifyText( string, request.getStartIndex(), request.getEndIndex(), - new TextClassifierImplNative.ClassificationOptions( + new AnnotatorModel.ClassificationOptions( refTime.toInstant().toEpochMilli(), refTime.getZone().getId(), localesString)); @@ -228,17 +230,17 @@ public final class TextClassifierImpl implements TextClassifier { ? request.getEntityConfig().resolveEntityListModifications( getEntitiesForHints(request.getEntityConfig().getHints())) : mSettings.getEntityListDefault(); - final TextClassifierImplNative nativeImpl = + final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales()); - final TextClassifierImplNative.AnnotatedSpan[] annotations = + final AnnotatorModel.AnnotatedSpan[] annotations = nativeImpl.annotate( textString, - new TextClassifierImplNative.AnnotationOptions( + new AnnotatorModel.AnnotationOptions( refTime.toInstant().toEpochMilli(), refTime.getZone().getId(), concatenateLocales(request.getDefaultLocales()))); - for (TextClassifierImplNative.AnnotatedSpan span : annotations) { - final TextClassifierImplNative.ClassificationResult[] results = + for (AnnotatorModel.AnnotatedSpan span : annotations) { + final AnnotatorModel.ClassificationResult[] results = span.getClassification(); if (results.length == 0 || !entitiesToIdentify.contains(results[0].getCollection())) { @@ -297,7 +299,7 @@ public final class TextClassifierImpl implements TextClassifier { } } - private TextClassifierImplNative getNative(LocaleList localeList) + private AnnotatorModel getNative(LocaleList localeList) throws FileNotFoundException { synchronized (mLock) { localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList; @@ -310,7 +312,7 @@ public final class TextClassifierImpl implements TextClassifier { destroyNativeIfExistsLocked(); final ParcelFileDescriptor fd = ParcelFileDescriptor.open( new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY); - mNative = new TextClassifierImplNative(fd.getFd()); + mNative = new AnnotatorModel(fd.getFd()); closeAndLogError(fd); mModel = bestModel; } @@ -398,14 +400,14 @@ public final class TextClassifierImpl implements TextClassifier { } private TextClassification createClassificationResult( - TextClassifierImplNative.ClassificationResult[] classifications, + AnnotatorModel.ClassificationResult[] classifications, String text, int start, int end, @Nullable Instant referenceTime) { final String classifiedText = text.substring(start, end); final TextClassification.Builder builder = new TextClassification.Builder() .setText(classifiedText); final int size = classifications.length; - TextClassifierImplNative.ClassificationResult highestScoringResult = null; + AnnotatorModel.ClassificationResult highestScoringResult = null; float highestScore = Float.MIN_VALUE; for (int i = 0; i < size; i++) { builder.setEntityType(classifications[i].getCollection(), @@ -486,9 +488,9 @@ public final class TextClassifierImpl implements TextClassifier { try { final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open( file, ParcelFileDescriptor.MODE_READ_ONLY); - final int version = TextClassifierImplNative.getVersion(modelFd.getFd()); + final int version = AnnotatorModel.getVersion(modelFd.getFd()); final String supportedLocalesStr = - TextClassifierImplNative.getLocales(modelFd.getFd()); + AnnotatorModel.getLocales(modelFd.getFd()); if (supportedLocalesStr.isEmpty()) { Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath()); return null; @@ -676,7 +678,7 @@ public final class TextClassifierImpl implements TextClassifier { public static List<LabeledIntent> create( Context context, @Nullable Instant referenceTime, - TextClassifierImplNative.ClassificationResult classification, + AnnotatorModel.ClassificationResult classification, String text) { final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH); text = text.trim(); diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java deleted file mode 100644 index 3d4c8f2863ea..000000000000 --- a/core/java/android/view/textclassifier/TextClassifierImplNative.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view.textclassifier; - -import android.content.res.AssetFileDescriptor; - -/** - * Java wrapper for TextClassifier native library interface. This library is used for detecting - * entities in text. - */ -final class TextClassifierImplNative { - - static { - System.loadLibrary("textclassifier"); - } - - private final long mModelPtr; - - /** - * Creates a new instance of TextClassifierImplNative, using the provided model image, given as - * a file descriptor. - */ - TextClassifierImplNative(int fd) { - mModelPtr = nativeNew(fd); - if (mModelPtr == 0L) { - throw new IllegalArgumentException("Couldn't initialize TC from file descriptor."); - } - } - - /** - * Creates a new instance of TextClassifierImplNative, using the provided model image, given as - * a file path. - */ - TextClassifierImplNative(String path) { - mModelPtr = nativeNewFromPath(path); - if (mModelPtr == 0L) { - throw new IllegalArgumentException("Couldn't initialize TC from given file."); - } - } - - /** - * Creates a new instance of TextClassifierImplNative, using the provided model image, given as - * an AssetFileDescriptor. - */ - TextClassifierImplNative(AssetFileDescriptor afd) { - mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength()); - if (mModelPtr == 0L) { - throw new IllegalArgumentException( - "Couldn't initialize TC from given AssetFileDescriptor"); - } - } - - /** - * Given a string context and current selection, computes the SmartSelection suggestion. - * - * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is - * the character index where the selection begins, and selectionEnd is the index of one - * character past the selection span. - * - * <p>The return value is an array of two ints: suggested selection beginning and end, with the - * same semantics as the input selectionBeginning and selectionEnd. - */ - public int[] suggestSelection( - String context, int selectionBegin, int selectionEnd, SelectionOptions options) { - return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options); - } - - /** - * Given a string context and current selection, classifies the type of the selected text. - * - * <p>The begin and end params are character indices in the context string. - * - * <p>Returns an array of ClassificationResult objects with the probability scores for different - * collections. - */ - public ClassificationResult[] classifyText( - String context, int selectionBegin, int selectionEnd, ClassificationOptions options) { - return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options); - } - - /** - * Annotates given input text. The annotations should cover the whole input context except for - * whitespaces, and are sorted by their position in the context string. - */ - public AnnotatedSpan[] annotate(String text, AnnotationOptions options) { - return nativeAnnotate(mModelPtr, text, options); - } - - /** Frees up the allocated memory. */ - public void close() { - nativeClose(mModelPtr); - } - - /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */ - public static String getLocales(int fd) { - return nativeGetLocales(fd); - } - - /** Returns the version of the model. */ - public static int getVersion(int fd) { - return nativeGetVersion(fd); - } - - /** Represents a datetime parsing result from classifyText calls. */ - public static final class DatetimeResult { - static final int GRANULARITY_YEAR = 0; - static final int GRANULARITY_MONTH = 1; - static final int GRANULARITY_WEEK = 2; - static final int GRANULARITY_DAY = 3; - static final int GRANULARITY_HOUR = 4; - static final int GRANULARITY_MINUTE = 5; - static final int GRANULARITY_SECOND = 6; - - private final long mTimeMsUtc; - private final int mGranularity; - - DatetimeResult(long timeMsUtc, int granularity) { - mGranularity = granularity; - mTimeMsUtc = timeMsUtc; - } - - public long getTimeMsUtc() { - return mTimeMsUtc; - } - - public int getGranularity() { - return mGranularity; - } - } - - /** Represents a result of classifyText method call. */ - public static final class ClassificationResult { - private final String mCollection; - private final float mScore; - private final DatetimeResult mDatetimeResult; - - ClassificationResult( - String collection, float score, DatetimeResult datetimeResult) { - mCollection = collection; - mScore = score; - mDatetimeResult = datetimeResult; - } - - public String getCollection() { - if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) { - switch (mDatetimeResult.getGranularity()) { - case DatetimeResult.GRANULARITY_HOUR: - // fall through - case DatetimeResult.GRANULARITY_MINUTE: - // fall through - case DatetimeResult.GRANULARITY_SECOND: - return TextClassifier.TYPE_DATE_TIME; - default: - return TextClassifier.TYPE_DATE; - } - } - return mCollection; - } - - public float getScore() { - return mScore; - } - - public DatetimeResult getDatetimeResult() { - return mDatetimeResult; - } - } - - /** Represents a result of Annotate call. */ - public static final class AnnotatedSpan { - private final int mStartIndex; - private final int mEndIndex; - private final ClassificationResult[] mClassification; - - AnnotatedSpan( - int startIndex, int endIndex, ClassificationResult[] classification) { - mStartIndex = startIndex; - mEndIndex = endIndex; - mClassification = classification; - } - - public int getStartIndex() { - return mStartIndex; - } - - public int getEndIndex() { - return mEndIndex; - } - - public ClassificationResult[] getClassification() { - return mClassification; - } - } - - /** Represents options for the suggestSelection call. */ - public static final class SelectionOptions { - private final String mLocales; - - SelectionOptions(String locales) { - mLocales = locales; - } - - public String getLocales() { - return mLocales; - } - } - - /** Represents options for the classifyText call. */ - public static final class ClassificationOptions { - private final long mReferenceTimeMsUtc; - private final String mReferenceTimezone; - private final String mLocales; - - ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { - mReferenceTimeMsUtc = referenceTimeMsUtc; - mReferenceTimezone = referenceTimezone; - mLocales = locale; - } - - public long getReferenceTimeMsUtc() { - return mReferenceTimeMsUtc; - } - - public String getReferenceTimezone() { - return mReferenceTimezone; - } - - public String getLocale() { - return mLocales; - } - } - - /** Represents options for the Annotate call. */ - public static final class AnnotationOptions { - private final long mReferenceTimeMsUtc; - private final String mReferenceTimezone; - private final String mLocales; - - AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { - mReferenceTimeMsUtc = referenceTimeMsUtc; - mReferenceTimezone = referenceTimezone; - mLocales = locale; - } - - public long getReferenceTimeMsUtc() { - return mReferenceTimeMsUtc; - } - - public String getReferenceTimezone() { - return mReferenceTimezone; - } - - public String getLocale() { - return mLocales; - } - } - - private static native long nativeNew(int fd); - - private static native long nativeNewFromPath(String path); - - private static native long nativeNewFromAssetFileDescriptor( - AssetFileDescriptor afd, long offset, long size); - - private static native int[] nativeSuggestSelection( - long context, - String text, - int selectionBegin, - int selectionEnd, - SelectionOptions options); - - private static native ClassificationResult[] nativeClassifyText( - long context, - String text, - int selectionBegin, - int selectionEnd, - ClassificationOptions options); - - private static native AnnotatedSpan[] nativeAnnotate( - long context, String text, AnnotationOptions options); - - private static native void nativeClose(long context); - - private static native String nativeGetLocales(int fd); - - private static native int nativeGetVersion(int fd); -} diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index ae6a2fd787d7..23d12374453f 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -25,6 +25,13 @@ import android.net.WebAddress; * Cookies are manipulated according to RFC2109. */ public abstract class CookieManager { + /** + * @deprecated This class should not be constructed by applications, use {@link #getInstance} + * instead to fetch the singleton instance. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public CookieManager() {} @Override protected Object clone() throws CloneNotSupportedException { diff --git a/core/java/android/webkit/RenderProcessGoneDetail.java b/core/java/android/webkit/RenderProcessGoneDetail.java index 0843e26ea19c..9beeaa5c1524 100644 --- a/core/java/android/webkit/RenderProcessGoneDetail.java +++ b/core/java/android/webkit/RenderProcessGoneDetail.java @@ -22,6 +22,13 @@ package android.webkit; **/ public abstract class RenderProcessGoneDetail { /** + * @deprecated This class should not be constructed by applications. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public RenderProcessGoneDetail() {} + + /** * Indicates whether the render process was observed to crash, or whether * it was killed by the system. * diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java index 7839a00eff69..ca33a0c659af 100644 --- a/core/java/android/webkit/SafeBrowsingResponse.java +++ b/core/java/android/webkit/SafeBrowsingResponse.java @@ -27,6 +27,12 @@ package android.webkit; * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}. */ public abstract class SafeBrowsingResponse { + /** + * @deprecated This class should not be constructed by applications. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public SafeBrowsingResponse() {} /** * Display the default interstitial. diff --git a/core/java/android/webkit/ServiceWorkerController.java b/core/java/android/webkit/ServiceWorkerController.java index 3517c74b680e..d7e0715a3770 100644 --- a/core/java/android/webkit/ServiceWorkerController.java +++ b/core/java/android/webkit/ServiceWorkerController.java @@ -38,6 +38,14 @@ import android.annotation.Nullable; public abstract class ServiceWorkerController { /** + * @deprecated This class should not be constructed by applications, use {@link #getInstance()} + * instead to fetch the singleton instance. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public ServiceWorkerController() {} + + /** * Returns the default ServiceWorkerController instance. At present there is * only one ServiceWorkerController instance for all WebView instances, * however this restriction may be relaxed in the future. diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java index 30f465cb42c6..99081827658a 100644 --- a/core/java/android/webkit/TracingController.java +++ b/core/java/android/webkit/TracingController.java @@ -43,6 +43,13 @@ import java.util.concurrent.Executor; * </pre></p> */ public abstract class TracingController { + /** + * @deprecated This class should not be constructed by applications, use {@link #getInstance} + * instead to fetch the singleton instance. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public TracingController() {} /** * Returns the default TracingController instance. At present there is diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java index f6166c58a4c9..f346c602c3b6 100644 --- a/core/java/android/webkit/WebViewDatabase.java +++ b/core/java/android/webkit/WebViewDatabase.java @@ -31,6 +31,14 @@ import android.content.Context; */ public abstract class WebViewDatabase { /** + * @deprecated This class should not be constructed by applications, use {@link + * #getInstance(Context)} instead to fetch the singleton instance. + */ + // TODO(ntfschr): mark this as @SystemApi after a year. + @Deprecated + public WebViewDatabase() {} + + /** * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} */ protected static final String LOGTAG = "webviewdatabase"; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index bbfac440d414..f95b3ce98264 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -321,6 +321,12 @@ import java.util.function.Supplier; * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize * @attr ref android.R.styleable#TextView_autoSizeStepGranularity * @attr ref android.R.styleable#TextView_autoSizePresetSizes + * @attr ref android.R.styleable#TextView_textCursorDrawable + * @attr ref android.R.styleable#TextView_textSelectHandle + * @attr ref android.R.styleable#TextView_textSelectHandleLeft + * @attr ref android.R.styleable#TextView_textSelectHandleRight + * @attr ref android.R.styleable#TextView_allowUndo + * @attr ref android.R.styleable#TextView_enabled */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 31f13c33c167..33b9ff7cee4f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -337,6 +337,9 @@ public class BatteryStatsImpl extends BatteryStats { private final PlatformIdleStateCallback mPlatformIdleStateCallback; + /** + * This handler is running on {@link BackgroundThread}. + */ final class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper, null, true); diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 9d5f0bcc54d9..ab50ad147107 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -130,6 +130,13 @@ message KeyguardControllerProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional bool keyguard_showing = 1; + repeated KeyguardOccludedProto keyguard_occluded_states= 2; +} + +message KeyguardOccludedProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 display_id = 1; optional bool keyguard_occluded = 2; } diff --git a/core/proto/android/server/backup_chunks_metadata.proto b/core/proto/android/server/backup_chunks_metadata.proto new file mode 100644 index 000000000000..a375f02545c5 --- /dev/null +++ b/core/proto/android/server/backup_chunks_metadata.proto @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +syntax = "proto2"; +package com.android.server.backup.encryption.chunk; + +option java_outer_classname = "ChunksMetadataProto"; + +// Cipher type with which the chunks are encrypted. For now we only support AES/GCM/NoPadding, but +// this is for backwards-compatibility in case we need to change the default Cipher in the future. +enum CipherType { + UNKNOWN_CIPHER_TYPE = 0; + // Chunk is prefixed with a 12-byte nonce. The tag length is 16 bytes. + AES_256_GCM = 1; +} + +// Checksum type with which the plaintext is verified. +enum ChecksumType { + UNKNOWN_CHECKSUM_TYPE = 0; + SHA_256 = 1; +} + +enum ChunkOrderingType { + CHUNK_ORDERING_TYPE_UNSPECIFIED = 0; + // The chunk ordering contains a list of the start position of each chunk in the encrypted file, + // ordered as in the plaintext file. This allows us to recreate the original plaintext file + // during decryption. We use this mode for full backups where the order of the data in the file + // is important. + EXPLICIT_STARTS = 1; + // The chunk ordering does not contain any start positions, and instead each encrypted chunk in + // the backup file is prefixed with its length. This allows us to decrypt each chunk but does + // not give any information about the order. However, we use this mode for key value backups + // where the order does not matter. + INLINE_LENGTHS = 2; +} + +// Chunk entry (for local state) +message Chunk { + // SHA-256 MAC of the plaintext of the chunk + optional bytes hash = 1; + // Number of bytes in encrypted chunk + optional int32 length = 2; +} + +// List of the chunks in the blob, along with the length of each chunk. From this is it possible to +// extract individual chunks. (i.e., start position is equal to the sum of the lengths of all +// preceding chunks.) +// +// This is local state stored on the device. It is never sent to the backup server. See +// ChunkOrdering for how the device restores the chunks in the correct order. +// Next tag : 6 +message ChunkListing { + repeated Chunk chunks = 1; + + // Cipher algorithm with which the chunks are encrypted. + optional CipherType cipher_type = 2; + + // Defines the type of chunk order used to encode the backup file on the server, so that we can + // consistently use the same type between backups. If unspecified this backup file was created + // before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS. + optional ChunkOrderingType chunk_ordering_type = 5; + + // The document ID returned from Scotty server after uploading the blob associated with this + // listing. This needs to be sent when uploading new diff scripts. + optional string document_id = 3; + + // Fingerprint mixer salt used for content defined chunking. This is randomly generated for each + // package during the initial non-incremental backup and reused for incremental backups. + optional bytes fingerprint_mixer_salt = 4; +} + +// Ordering information about plaintext and checksum. This is used on restore to reconstruct the +// blob in its correct order. (The chunk order is randomized so as to give the server less +// information about which parts of the backup are changing over time.) This proto is encrypted +// before being uploaded to the server, with a key unknown to the server. +message ChunkOrdering { + // For backups where ChunksMetadata#chunk_ordering_type = EXPLICIT STARTS: + // Ordered start positions of chunks. i.e., the file is the chunk starting at this position, + // followed by the chunk starting at this position, followed by ... etc. You can compute the + // lengths of the chunks by sorting this list then looking at the start position of the next + // chunk after the chunk you care about. This is guaranteed to work as all chunks are + // represented in this list. + // + // For backups where ChunksMetadata#chunk_ordering_type = INLINE_LENGTHS: + // This field is unused. See ChunkOrderingType#INLINE_LENGTHS. + repeated int32 starts = 1 [packed = true]; + + // Checksum of plaintext content. (i.e., in correct order.) + // + // Each chunk also has a MAC, as generated by GCM, so this is NOT Mac-then-Encrypt, which has + // security implications. This is an additional checksum to verify that once the chunks have + // been reordered, that the file matches the expected plaintext. This prevents the device + // restoring garbage data in case of a mismatch between the ChunkOrdering and the backup blob. + optional bytes checksum = 2; +} + +// Additional metadata about a backup blob that needs to be synced to the server. This is used on +// restore to reconstruct the blob in its correct order. (The chunk order is randomized so as to +// give the server less information about which parts of the backup are changing over time.) This +// data structure is only ever uploaded to the server encrypted with a key unknown to the server. +// Next tag : 6 +message ChunksMetadata { + // Cipher algorithm with which the chunk listing and chunks are encrypted. + optional CipherType cipher_type = 1; + + // Defines the type of chunk order this metadata contains. If unspecified this backup file was + // created before INLINE_LENGTHS was supported, thus assume it is EXPLICIT_STARTS. + optional ChunkOrderingType chunk_ordering_type = 5 + [default = CHUNK_ORDERING_TYPE_UNSPECIFIED]; + + // Encrypted bytes of ChunkOrdering + optional bytes chunk_ordering = 2; + + // The type of algorithm used for the checksum of the plaintext. (See ChunkOrdering.) This is + // for forwards compatibility in case we change the algorithm in the future. For now, always + // SHA-256. + optional ChecksumType checksum_type = 3; + + // This used to be the plaintext tertiary key. No longer used. + reserved 4; +}
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5a1f2e8d870c..ade0b111111d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4144,6 +4144,10 @@ <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" android:protectionLevel="signature" /> + <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. --> + <permission android:name="android.permission.BIND_SMS_APP_SERVICE" + android:protectionLevel="signature" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/values/colors_car.xml b/core/res/res/values/colors_car.xml index 6053728369e1..32671ac8f752 100644 --- a/core/res/res/values/colors_car.xml +++ b/core/res/res/values/colors_car.xml @@ -17,15 +17,271 @@ */ --> <resources> - <!-- car support colors from - https://cs.corp.google.com/android/frameworks/support/car/res/values/colors.xml --> - <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color> - <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color> - <color name="car_card_dark">@color/car_dark_blue_grey_700</color> - <color name="car_body1_light">@color/car_grey_100</color> - - <color name="car_grey_50">#fffafafa</color> - <color name="car_grey_900">#ff212121</color> - <color name="car_dark_blue_grey_700">#ff172026</color> - <color name="car_grey_100">#fff5f5f5</color> + <color name="car_background">@color/black</color> + + <color name="car_colorPrimary">@color/car_grey_868</color> + <color name="car_colorSecondary">@color/car_grey_900</color> + <color name="car_colorPrimaryDark">@color/car_grey_958</color> + + + <!-- Various colors for text sizes. "Light" and "dark" here refer to the lighter or darker + shades. --> + <color name="car_title_light">@color/car_grey_100</color> + <color name="car_title_dark">@color/car_grey_900</color> + <color name="car_title">@color/car_title_light</color> + + <color name="car_title2_light">@color/car_grey_100</color> + <color name="car_title2_dark">@color/car_grey_900</color> + <color name="car_title2">@color/car_title2_light</color> + + <color name="car_headline1_light">@color/car_grey_100</color> + <color name="car_headline1_dark">@color/car_grey_800</color> + <color name="car_headline1">@color/car_headline1_light</color> + + <color name="car_headline2_light">@color/car_grey_100</color> + <color name="car_headline2_dark">@color/car_grey_900</color> + <color name="car_headline2">@color/car_headline2_light</color> + + <color name="car_headline3_light">@android:color/white</color> + <color name="car_headline3_dark">@color/car_grey_900</color> + <color name="car_headline3">@color/car_headline3_light</color> + + <color name="car_headline4_light">@android:color/white</color> + <color name="car_headline4_dark">@android:color/black</color> + <color name="car_headline4">@color/car_headline4_light</color> + + <color name="car_body1_light">@color/car_grey_100</color> + <color name="car_body1_dark">@color/car_grey_900</color> + <color name="car_body1">@color/car_body1_light</color> + + <color name="car_body2_light">@color/car_grey_300</color> + <color name="car_body2_dark">@color/car_grey_700</color> + <color name="car_body2">@color/car_body2_light</color> + + <color name="car_body3_light">@android:color/white</color> + <color name="car_body3_dark">@android:color/black</color> + <color name="car_body3">@color/car_body3_light</color> + + <color name="car_body4_light">@android:color/white</color> + <color name="car_body4_dark">@android:color/black</color> + <color name="car_body4">@color/car_body4_light</color> + + <color name="car_action1_light">@color/car_grey_900</color> + <color name="car_action1_dark">@color/car_grey_50</color> + <color name="car_action1">@color/car_action1_light</color> + + <!-- The tinting colors to create a light- and dark-colored icon respectively. --> + <color name="car_tint_light">@color/car_grey_50</color> + <color name="car_tint_dark">@color/car_grey_900</color> + + <!-- The tinting color for an icon. This icon is assumed to be on a light background. --> + <color name="car_tint">@color/car_tint_light</color> + + <!-- An inverted tinting from car_tint. --> + <color name="car_tint_inverse">@color/car_tint_dark</color> + + <!-- The color of the divider. The color here is a lighter shade. --> + <color name="car_list_divider_light">#1fffffff</color> + + <!-- The color of the divider. The color here is a darker shade. --> + <color name="car_list_divider_dark">#1f000000</color> + + <!-- The color of the dividers in the list. This color is assumed to be on a light colored + view. --> + <color name="car_list_divider">@color/car_list_divider_light</color> + + <!-- A light and dark colored card. --> + <color name="car_card_light">@color/car_grey_50</color> + <color name="car_card_dark">@color/car_dark_blue_grey_700</color> + + <!-- The default color of a card in car UI. --> + <color name="car_card">@color/car_card_dark</color> + + <!-- The ripple colors. The "dark" and "light" designation here refers to the color of the + ripple itself. --> + <color name="car_card_ripple_background_dark">#8F000000</color> + <color name="car_card_ripple_background_light">#27ffffff</color> + + <!-- The ripple color for a light colored card. --> + <color name="car_card_ripple_background">@color/car_card_ripple_background_light</color> + + <!-- The ripple color for a dark-colored card. This color is the opposite of + car_card_ripple_background. --> + <color name="car_card_ripple_background_inverse">@color/car_card_ripple_background_dark</color> + + <!-- The top margin before the start of content in an application. --> + <dimen name="app_header_height">96dp</dimen> + + <!-- The lighter and darker color for the scrollbar thumb. --> + <color name="car_scrollbar_thumb_light">#99ffffff</color> + <color name="car_scrollbar_thumb_dark">#7f0b0f12</color> + + <!-- The color of the scroll bar indicator in the PagedListView. This color is assumed to be on + a light-colored background. --> + <color name="car_scrollbar_thumb">@color/car_scrollbar_thumb_light</color> + + <!-- The inverted color of the scroll bar indicator. This color is always the opposite of + car_scrollbar_thumb. --> + <color name="car_scrollbar_thumb_inverse">@color/car_scrollbar_thumb_dark</color> + + <!-- The color of the seekbar track secondary progress in SeekbarListItem. --> + <color name="car_seekbar_track_secondary_progress">@color/car_grey_500</color> + + <!-- The lighter and darker color for the seekbar track background. --> + <color name="car_seekbar_track_background_light">@color/car_grey_400</color> + <color name="car_seekbar_track_background_dark">@color/car_grey_700</color> + <!-- The color of the seekbar track background in SeekbarListItem. This color is assumed to be + on a light-colored background. --> + <color name="car_seekbar_track_background">@color/car_seekbar_track_background_dark</color> + <!-- background is car_grey_868 with .9 alpha --> + <color name="car_toast_background">#E6282a2d</color> + + <!-- Misc colors --> + <color name="car_highlight_light">@color/car_teal_700</color> + <color name="car_highlight_dark">@color/car_teal_200</color> + <color name="car_highlight">@color/car_highlight_dark</color> + <color name="car_accent_light">@color/car_highlight_light</color> + <color name="car_accent_dark">@color/car_highlight_dark</color> + <color name="car_accent">@color/car_highlight_dark</color> + + <color name="car_user_switcher_user_image_bgcolor">@color/car_grey_50</color> + <color name="car_user_switcher_user_image_fgcolor">@color/car_grey_900</color> + + <!-- Color palette for cars --> + <color name="car_grey_958">#ff0e1013</color> + <color name="car_grey_928">#ff17181b</color> + <color name="car_grey_900">#ff202124</color> + <color name="car_grey_868">#ff282a2d</color> + <color name="car_grey_846">#ff2e3234</color> + <color name="car_grey_800">#ff3c4043</color> + <color name="car_grey_772">#ff464a4d</color> + <color name="car_grey_746">#ff4d5256</color> + <color name="car_grey_700">#ff5f6368</color> + <color name="car_grey_600">#ff80868b</color> + <color name="car_grey_500">#ff9aa0a6</color> + <color name="car_grey_400">#ffbdc1c6</color> + <color name="car_grey_300">#ffdadce0</color> + <color name="car_grey_200">#ffe8eaed</color> + <color name="car_grey_100">#fff1f3f4</color> + <color name="car_grey_50">#fff8f9fa</color> + + <color name="car_blue_900">#ff1d57a9</color> + <color name="car_blue_800">#ff2065bb</color> + <color name="car_blue_700">#ff2374ce</color> + <color name="car_blue_600">#ff2581df</color> + <color name="car_blue_500">#ff5195ea</color> + <color name="car_blue_400">#ff6ba5ed</color> + <color name="car_blue_300">#ff96bff2</color> + <color name="car_blue_200">#ffb9d4f6</color> + <color name="car_blue_100">#ffd9e6f9</color> + <color name="car_blue_50">#ffebf1fc</color> + + <color name="car_green_900">#ff136e39</color> + <color name="car_green_800">#ff1b7e42</color> + <color name="car_green_700">#ff218c48</color> + <color name="car_green_600">#ff28994f</color> + <color name="car_green_500">#ff41af6a</color> + <color name="car_green_400">#ff5dba80</color> + <color name="car_green_300">#ff8dcfa5</color> + <color name="car_green_200">#ffb3dfc3</color> + <color name="car_green_100">#ffd5ebdf</color> + <color name="car_green_50">#ffe8f3ee</color> + + <color name="car_red_900">#ffa81314</color> + <color name="car_red_800">#ffb41b1a</color> + <color name="car_red_700">#ffc22a2a</color> + <color name="car_red_600">#ffd33b30</color> + <color name="car_red_500">#ffe25142</color> + <color name="car_red_400">#ffe66a5e</color> + <color name="car_red_300">#ffed968d</color> + <color name="car_red_200">#fff3b9b3</color> + <color name="car_red_100">#fff7d8d9</color> + <color name="car_red_50">#fffaebeb</color> + + <color name="car_yellow_900">#ffdd860e</color> + <color name="car_yellow_800">#ffe59810</color> + <color name="car_yellow_700">#ffeda912</color> + <color name="car_yellow_600">#fff3b713</color> + <color name="car_yellow_500">#fff5c518</color> + <color name="car_yellow_400">#fff6cd3a</color> + <color name="car_yellow_300">#fff9dc74</color> + <color name="car_yellow_200">#fffbe7a2</color> + <color name="car_yellow_100">#fffcf0ce</color> + <color name="car_yellow_50">#fffdf7e6</color> + + <color name="car_orange_900">#ffb06000</color> + <color name="car_orange_800">#ffc26401</color> + <color name="car_orange_700">#ffd56e0c</color> + <color name="car_orange_600">#ffe8710a</color> + <color name="car_orange_500">#fffa7b17</color> + <color name="car_orange_400">#fffa903e</color> + <color name="car_orange_300">#fffcad70</color> + <color name="car_orange_200">#fffdc69c</color> + <color name="car_orange_100">#fffedfc8</color> + <color name="car_orange_50">#fffeefe3</color> + + <color name="car_pink_900">#ff9c166b</color> + <color name="car_pink_800">#ffb80672</color> + <color name="car_pink_700">#ffd01884</color> + <color name="car_pink_600">#ffe52592</color> + <color name="car_pink_500">#fff439a0</color> + <color name="car_pink_400">#ffff63b8</color> + <color name="car_pink_300">#ffff8bcb</color> + <color name="car_pink_200">#fffba9d6</color> + <color name="car_pink_100">#fffdcfe8</color> + <color name="car_pink_50">#fffde7f3</color> + + <color name="car_teal_900">#ff004d40</color> + <color name="car_teal_800">#ff00695c</color> + <color name="car_teal_700">#ff00796b</color> + <color name="car_teal_600">#ff00897b</color> + <color name="car_teal_500">#ff009688</color> + <color name="car_teal_400">#ff26a69a</color> + <color name="car_teal_300">#ff4db6ac</color> + <color name="car_teal_200">#ff80cbc4</color> + <color name="car_teal_100">#ffb2dfdb</color> + <color name="car_teal_50">#ffe0f2f1</color> + + <color name="car_purple_900">#ff681da8</color> + <color name="car_purple_800">#ff7627bb</color> + <color name="car_purple_700">#ff8430ce</color> + <color name="car_purple_600">#ff9334e6</color> + <color name="car_purple_500">#ffa142f4</color> + <color name="car_purple_400">#ffaf5cf7</color> + <color name="car_purple_300">#ffc58af9</color> + <color name="car_purple_200">#ffd7aefb</color> + <color name="car_purple_100">#ffe9d2fd</color> + <color name="car_purple_50">#fff3e8fd</color> + + <color name="car_cyan_900">#ff01877e</color> + <color name="car_cyan_800">#ff099091</color> + <color name="car_cyan_700">#ff12a4af</color> + <color name="car_cyan_600">#ff12b5cb</color> + <color name="car_cyan_500">#ff24c1e0</color> + <color name="car_cyan_400">#ff4ecde6</color> + <color name="car_cyan_300">#ff78d9ec</color> + <color name="car_cyan_200">#ffa1e4f2</color> + <color name="car_cyan_100">#ffcbf0f8</color> + <color name="car_cyan_50">#ffe4f7fb</color> + + + <color name="car_grey_1000">#cc000000</color> + <color name="car_white_1000">#1effffff</color> + <color name="car_blue_grey_800">#ff37474F</color> + <color name="car_blue_grey_900">#ff263238</color> + <color name="car_dark_blue_grey_600">#ff1d272d</color> + <color name="car_dark_blue_grey_700">#ff172026</color> + <color name="car_dark_blue_grey_800">#ff11181d</color> + <color name="car_dark_blue_grey_900">#ff0c1013</color> + <color name="car_dark_blue_grey_1000">#ff090c0f</color> + <color name="car_light_blue_300">#ff4fc3f7</color> + <color name="car_light_blue_500">#ff03A9F4</color> + <color name="car_light_blue_600">#ff039be5</color> + <color name="car_light_blue_700">#ff0288d1</color> + <color name="car_light_blue_800">#ff0277bd</color> + <color name="car_light_blue_900">#ff01579b</color> + + + <color name="car_red_500a">#ffd50000</color> + <color name="car_red_a700">#ffd50000</color> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1404383bc234..9aebf6c4597f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3541,4 +3541,13 @@ <!-- Brand value for attestation of misprovisioned device. --> <string name="config_misprovisionedBrandValue" translatable="false"></string> + + <!-- Pre-scale volume at volume step 1 for Absolute Volume --> + <fraction name="config_prescaleAbsoluteVolume_index1">50%</fraction> + + <!-- Pre-scale volume at volume step 2 for Absolute Volume --> + <fraction name="config_prescaleAbsoluteVolume_index2">70%</fraction> + + <!-- Pre-scale volume at volume step 3 for Absolute Volume --> + <fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction> </resources> diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index 7d14f868fefc..a0c02ede1890 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -16,12 +16,86 @@ */ --> <resources> - <!-- TODO replace with car support lib sizes when available --> <dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen> <dimen name="car_fullscreen_user_pod_width">243dp</dimen> <dimen name="car_fullscreen_user_pod_height">356dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen> - <dimen name="car_padding_4">20dp</dimen> + + + <!-- Application Bar --> + <dimen name="car_app_bar_height">80dp</dimen> + <!-- Margin --> + <dimen name="car_margin">20dp</dimen> + <!-- Lists --> + <dimen name="car_single_line_list_item_height">96dp</dimen> + <dimen name="car_double_line_list_item_height">@dimen/car_single_line_list_item_height</dimen> + <dimen name="car_list_divider_height">1dp</dimen> + <!-- The diff between keyline 1 and keyline 3. --> + <dimen name="car_keyline_1_keyline_3_diff">88dp</dimen> + <dimen name="car_dialog_action_bar_height">@dimen/car_card_action_bar_height</dimen> + <dimen name="car_primary_icon_size">44dp</dimen> + + <!-- Text size for car --> + <dimen name="car_title_size">32sp</dimen> + <dimen name="car_title2_size">32sp</dimen> + <dimen name="car_headline1_size">45sp</dimen> + <dimen name="car_headline2_size">32sp</dimen> + <dimen name="car_headline3_size">24sp</dimen> + <dimen name="car_headline4_size">20sp</dimen> <dimen name="car_body1_size">32sp</dimen> -</resources>
\ No newline at end of file + <dimen name="car_body2_size">26sp</dimen> + <dimen name="car_body3_size">16sp</dimen> + <dimen name="car_body4_size">14sp</dimen> + <dimen name="car_body5_size">18sp</dimen> + <dimen name="car_label1_size">26sp</dimen> + <dimen name="car_label2_size">64sp</dimen> + <dimen name="car_action1_size">26sp</dimen> + <dimen name="car_action2_size">26sp</dimen> + + <!-- Common icon size for car app --> + <dimen name="car_icon_size">56dp</dimen> + + <dimen name="car_card_header_height">96dp</dimen> + <dimen name="car_card_action_bar_height">96dp</dimen> + + <!-- Paddings --> + <dimen name="car_padding_1">4dp</dimen> + <dimen name="car_padding_2">10dp</dimen> + <dimen name="car_padding_3">16dp</dimen> + <dimen name="car_padding_4">28dp</dimen> + <dimen name="car_padding_5">32dp</dimen> + + <!-- Radius --> + <dimen name="car_radius_1">4dp</dimen> + <dimen name="car_radius_2">8dp</dimen> + <dimen name="car_radius_3">16dp</dimen> + <dimen name="car_radius_5">100dp</dimen> + + <!-- Keylines for content. --> + <dimen name="car_keyline_1">48dp</dimen> + <dimen name="car_keyline_2">108dp</dimen> + <dimen name="car_keyline_3">152dp</dimen> + <dimen name="car_keyline_4">182dp</dimen> + + <!-- Buttons --> + <dimen name="car_button_height">56dp</dimen> + <dimen name="car_button_min_width">158dp</dimen> + <dimen name="car_button_horizontal_padding">@dimen/car_padding_4</dimen> + <dimen name="car_borderless_button_horizontal_padding">0dp</dimen> + <dimen name="car_button_radius">@dimen/car_radius_1</dimen> + <dimen name="car_pill_button_size">56dp</dimen> + + <!-- Seekbar --> + <dimen name="car_seekbar_height">6dp</dimen> + <dimen name="car_seekbar_padding">26dp</dimen> + <dimen name="car_seekbar_thumb_size">24dp</dimen> + <dimen name="car_seekbar_thumb_stroke">1dp</dimen> + <!-- The space between seekbar and text in ListItem. This value is based on car_seekbar_padding. + It brings seekbar and text closer for visual balance while maintaining touch area. --> + <dimen name="car_seekbar_text_overlap">-20dp</dimen> + + <!-- Progress Bar --> + <dimen name="car_progress_bar_height">@dimen/car_seekbar_height</dimen> + +</resources> diff --git a/core/res/res/values/styles_car.xml b/core/res/res/values/styles_car.xml new file mode 100644 index 000000000000..f6ff1b651788 --- /dev/null +++ b/core/res/res/values/styles_car.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- Car text --> + <style name="CarBody1"> + <item name="textStyle">normal</item> + <item name="textSize">@dimen/car_body1_size</item> + <item name="textColor">@color/car_body1</item> + </style> + + <style name="CarBody1.Light"> + <item name="textColor">@color/car_body1_light</item> + </style> + + <style name="CarBody1.Dark"> + <item name="textColor">@color/car_body2_dark</item> + </style> + + <style name="CarBody2"> + <item name="textStyle">normal</item> + <item name="textSize">@dimen/car_body2_size</item> + <item name="textColor">@color/car_body2</item> + </style> + + <style name="CarBody2.Dark"> + <item name="textColor">@color/car_body2_dark</item> + </style> + <style name="CarBody2.Light"> + <item name="textColor">@color/car_body2_light</item> + </style> + + <style name="CarBody3"> + <item name="textStyle">normal</item> + <item name="textSize">@dimen/car_body3_size</item> + <item name="textColor">@color/car_body3</item> + </style> + + <!-- The smallest styling for body text. The color of this text changes based on the day/night + mode. --> + <style name="CarBody4"> + <item name="textStyle">normal</item> + <item name="textSize">@dimen/car_body4_size</item> + <item name="textColor">@color/car_body4</item> + </style> + + <style name="CarAction1"> + <item name="textStyle">bold</item> + <item name="textSize">@dimen/car_action1_size</item> + <item name="textColor">@color/car_highlight</item> + </style> + + <style name="CarAction1.Dark"> + <item name="textColor">@color/car_highlight_dark</item> + </style> + <style name="CarAction1.Light"> + <item name="textColor">@color/car_highlight_light</item> + </style> + + <!-- The styling for title text. The color of this text changes based on day/night mode. --> + <style name="CarTitle" > + <item name="textStyle">bold</item> + <item name="textSize">@dimen/car_title2_size</item> + <item name="textColor">@color/car_title</item> + </style> + + <!-- Title text that is permanently a dark color. --> + <style name="CarTitle.Dark" > + <item name="textColor">@color/car_title_dark</item> + </style> + + <!-- Title text that is permanently a light color. --> + <style name="CarTitle.Light" > + <item name="textColor">@color/car_title_light</item> + </style> + +</resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 21f0dad69e2c..9f2256a6461a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3470,4 +3470,9 @@ <java-symbol type="integer" name="db_wal_truncate_size" /> <java-symbol type="integer" name="config_wakeUpDelayDoze" /> <java-symbol type="string" name="config_dozeWakeScreenSensorType" /> + + <!-- For Bluetooth AbsoluteVolume --> + <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" /> + <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" /> + <java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 442106b988e1..3385527ee6ff 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1716,4 +1716,10 @@ easier. <item name="colorAccent">@color/accent_device_default_dark</item> </style> + <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen"> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorBackgroundFloating">@color/background_device_default_light</item> + <item name="layout_gravity">center</item> + </style> + </resources> diff --git a/media/lib/remotedisplay/OWNERS b/media/lib/remotedisplay/OWNERS new file mode 100644 index 000000000000..7e7335d68d3b --- /dev/null +++ b/media/lib/remotedisplay/OWNERS @@ -0,0 +1 @@ +michaelwr@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 2887a08cad06..750a8438c00d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -34,7 +34,6 @@ import com.android.settingslib.R; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import androidx.annotation.VisibleForTesting; @@ -59,7 +58,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private long mHiSyncId; // Need this since there is no method for getting RSSI private short mRssi; - private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState; private final List<LocalBluetoothProfile> mProfiles = new ArrayList<LocalBluetoothProfile>(); @@ -101,7 +99,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> mLocalAdapter = BluetoothAdapter.getDefaultAdapter(); mProfileManager = profileManager; mDevice = device; - mProfileConnectionState = new HashMap<>(); fillData(); mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID; } @@ -134,7 +131,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } return; } - mProfileConnectionState.put(profile, newProfileState); if (newProfileState == BluetoothProfile.STATE_CONNECTED) { if (profile instanceof MapProfile) { profile.setPreferred(mDevice, true); @@ -324,22 +320,9 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } public int getProfileConnectionState(LocalBluetoothProfile profile) { - if (mProfileConnectionState.get(profile) == null) { - // If cache is empty make the binder call to get the state - int state = profile.getConnectionStatus(mDevice); - mProfileConnectionState.put(profile, state); - } - return mProfileConnectionState.get(profile); - } - - public void clearProfileConnectionState () - { - if (BluetoothUtils.D) { - Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName()); - } - for (LocalBluetoothProfile profile :getProfiles()) { - mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED); - } + return profile != null + ? profile.getConnectionStatus(mDevice) + : BluetoothProfile.STATE_DISCONNECTED; } // TODO: do any of these need to run async on a background thread? diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 5a64e02cece4..21cf0c27a8d5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -285,11 +285,6 @@ public class CachedBluetoothDeviceManager { { mCachedDevicesMapForHearingAids.remove(cachedDevice.getHiSyncId()); } - } else { - // For bonded devices, we need to clear the connection status so that - // when BT is enabled next time, device connection status shall be retrieved - // by making a binder call. - cachedDevice.clearProfileConnectionState(); } } for (int i = mHearingAidDevicesNotAddedInCache.size() - 1; i >= 0; i--) { @@ -297,11 +292,6 @@ public class CachedBluetoothDeviceManager { if (notCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) { notCachedDevice.setJustDiscovered(false); mHearingAidDevicesNotAddedInCache.remove(i); - } else { - // For bonded devices, we need to clear the connection status so that - // when BT is enabled next time, device connection status shall be retrieved - // by making a binder call. - notCachedDevice.clearProfileConnectionState(); } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 7000f9d7a7d2..0c29f431ef3f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -290,10 +290,11 @@ public class LocalBluetoothProfileManager { } } - mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState, - mProfile.getProfileId()); cachedDevice.onProfileStateChanged(mProfile, newState); cachedDevice.refresh(); + // Dispatch profile changed after device update + mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState, + mProfile.getProfileId()); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index 7baded8da1d4..62b5688fc9e6 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -118,7 +118,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify addDevice(). */ @Test - public void testAddDevice_validCachedDevices_devicesAdded() { + public void addDevice_validCachedDevices_devicesAdded() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -136,7 +136,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify getName(). */ @Test - public void testGetName_validCachedDevice_nameFound() { + public void getName_validCachedDevice_nameFound() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); assertThat(mCachedDeviceManager.getName(mDevice1)).isEqualTo(DEVICE_ALIAS_1); @@ -146,7 +146,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onDeviceNameUpdated(). */ @Test - public void testOnDeviceNameUpdated_validName_nameUpdated() { + public void onDeviceNameUpdated_validName_nameUpdated() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); assertThat(cachedDevice1.getName()).isEqualTo(DEVICE_ALIAS_1); @@ -161,7 +161,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify clearNonBondedDevices(). */ @Test - public void testClearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() { + public void clearNonBondedDevices_bondedAndNonBondedDevices_nonBondedDevicesCleared() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -193,7 +193,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify clearNonBondedDevices() for hearing aids. */ @Test - public void testClearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() { + public void clearNonBondedDevices_HearingAids_nonBondedHAsClearedFromCachedDevicesMap() { when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); @@ -214,7 +214,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId. */ @Test - public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() { + public void onHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -247,7 +247,7 @@ public class CachedBluetoothDeviceManagerTest { * device is connected and other is disconnected. The connected device should be chosen. */ @Test - public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() { + public void onHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -282,7 +282,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId. */ @Test - public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() { + public void onHiSyncIdChanged_differentHiSyncId_populateInSameList() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -316,7 +316,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onProfileConnectionStateChanged() for single hearing aid device connection. */ @Test - public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() { + public void onProfileConnectionStateChanged_singleDeviceConnected_visible() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); @@ -353,7 +353,7 @@ public class CachedBluetoothDeviceManagerTest { * devices are disconnected and they get connected. */ @Test - public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() { + public void onProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -405,7 +405,7 @@ public class CachedBluetoothDeviceManagerTest { * devices are connected and they get disconnected. */ @Test - public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() { + public void onProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -458,7 +458,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair. */ @Test - public void testOnDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() { + public void onDeviceUnpaired_bothHearingAidsPaired_removesItsPairFromList() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -488,7 +488,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify OnDeviceUnpaired() for paired hearing Aid devices which are not a pair. */ @Test - public void testOnDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() { + public void onDeviceUnpaired_bothHearingAidsNotPaired_doesNotRemoveAnyDeviceFromList() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -532,7 +532,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify addDevice() for hearing aid devices with same HiSyncId. */ @Test - public void testAddDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() { + public void addDevice_hearingAidDevicesWithSameHiSyncId_populateInDifferentLists() { doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager) .getHearingAidProfile(); doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -560,7 +560,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify addDevice() for hearing aid devices with different HiSyncId. */ @Test - public void testAddDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() { + public void addDevice_hearingAidDevicesWithDifferentHiSyncId_populateInSameList() { doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager) .getHearingAidProfile(); doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -592,7 +592,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify getHearingAidPairDeviceSummary() for hearing aid devices with same HiSyncId. */ @Test - public void testGetHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() { + public void getHearingAidPairDeviceSummary_bothHearingAidsPaired_returnsSummaryOfPair() { mCachedDevice1.setHiSyncId(HISYNCID1); mCachedDevice2.setHiSyncId(HISYNCID1); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); @@ -609,7 +609,7 @@ public class CachedBluetoothDeviceManagerTest { * HiSyncId. */ @Test - public void testGetHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() { + public void getHearingAidPairDeviceSummary_bothHearingAidsNotPaired_returnsNull() { mCachedDevice1.setHiSyncId(HISYNCID1); mCachedDevice2.setHiSyncId(HISYNCID2); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); @@ -625,7 +625,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify updateHearingAidsDevices(). */ @Test - public void testUpdateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() { + public void updateHearingAidDevices_hiSyncIdAvailable_setsHiSyncId() { doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager) .getHearingAidProfile(); doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); @@ -643,7 +643,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onBtClassChanged(). */ @Test - public void testOnBtClassChanged_validBtClass_classChanged() { + public void onBtClassChanged_validBtClass_classChanged() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1); @@ -658,7 +658,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onDeviceDisappeared(). */ @Test - public void testOnDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() { + public void onDeviceDisappeared_deviceBondedUnbonded_unbondedDeviceDisappeared() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); @@ -673,7 +673,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onActiveDeviceChanged(). */ @Test - public void testOnActiveDeviceChanged_connectedDevices_activeDeviceChanged() { + public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -736,7 +736,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid. */ @Test - public void testOnActiveDeviceChanged_withA2dpAndHearingAid() { + public void onActiveDeviceChanged_withA2dpAndHearingAid() { CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); assertThat(cachedDevice1).isNotNull(); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index c18db11a71a3..f6201dd0b5f1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -79,74 +80,74 @@ public class CachedBluetoothDeviceTest { } @Test - public void testGetConnectionSummary_testSingleProfileConnectDisconnect() { + public void getConnectionSummary_testSingleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Test with battery level mBatteryLevel = 10; // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); } @Test - public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() { + public void getConnectionSummary_testMultipleProfileConnectDisconnect() { mBatteryLevel = 10; // Set HFP, A2DP and PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); // Disconnect HFP only and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( "10% battery"); // Disconnect A2DP only and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( "10% battery"); // Disconnect both HFP and A2DP and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( "10% battery"); // Disconnect all profiles and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); } @Test - public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() { + public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() { // Test without battery level // Set A2DP profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set device as Active for A2DP and test connection state summary @@ -159,26 +160,26 @@ public class CachedBluetoothDeviceTest { "Active, 10% battery"); // Set A2DP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set A2DP profile to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); // Set A2DP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); } @Test - public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() { + public void getConnectionSummary_testSingleProfileActiveDeviceHfp() { // Test without battery level // Set HFP profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set device as Active for HFP and test connection state summary @@ -193,26 +194,26 @@ public class CachedBluetoothDeviceTest { "Active, 10% battery"); // Set HFP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set HFP profile to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); // Set HFP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); } @Test - public void testGetConnectionSummary_testSingleProfileActiveDeviceHearingAid() { + public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() { // Test without battery level // Set Hearing Aid profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set device as Active for Hearing Aid and test connection state summary @@ -227,11 +228,11 @@ public class CachedBluetoothDeviceTest { } @Test - public void testGetConnectionSummary_testMultipleProfilesActiveDevice() { + public void getConnectionSummary_testMultipleProfilesActiveDevice() { // Test without battery level // Set A2DP and HFP profiles to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); // Set device as Active for A2DP and HFP and test connection state summary @@ -246,14 +247,14 @@ public class CachedBluetoothDeviceTest { // Disconnect A2DP only and test connection state summary mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( "10% battery"); // Disconnect HFP only and test connection state summary mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( "Active, 10% battery"); @@ -261,15 +262,15 @@ public class CachedBluetoothDeviceTest { // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set A2DP and HFP profiles to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); // Set A2DP and HFP profiles to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getConnectionSummary()).isNull(); } @@ -277,32 +278,32 @@ public class CachedBluetoothDeviceTest { public void getCarConnectionSummary_singleProfileConnectDisconnect() { // Test without battery level // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); // Test with battery level mBatteryLevel = 10; // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%"); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set PAN profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @@ -311,29 +312,29 @@ public class CachedBluetoothDeviceTest { mBatteryLevel = 10; // Set HFP, A2DP and PAN profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%"); // Disconnect HFP only and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( "Connected (no phone), battery 10%"); // Disconnect A2DP only and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( "Connected (no media), battery 10%"); // Disconnect both HFP and A2DP and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( "Connected (no phone or media), battery 10%"); // Disconnect all profiles and test connection state summary - mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @@ -341,7 +342,7 @@ public class CachedBluetoothDeviceTest { public void getCarConnectionSummary_singleProfileActiveDeviceA2dp() { // Test without battery level // Set A2DP profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set device as Active for A2DP and test connection state summary @@ -354,18 +355,18 @@ public class CachedBluetoothDeviceTest { "Connected, battery 10%, active (media)"); // Set A2DP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set A2DP profile to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)"); // Set A2DP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @@ -373,7 +374,7 @@ public class CachedBluetoothDeviceTest { public void getCarConnectionSummary_singleProfileActiveDeviceHfp() { // Test without battery level // Set HFP profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set device as Active for HFP and test connection state summary @@ -386,18 +387,18 @@ public class CachedBluetoothDeviceTest { "Connected, battery 10%, active (phone)"); // Set HFP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set HFP profile to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)"); // Set HFP profile to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @@ -405,7 +406,7 @@ public class CachedBluetoothDeviceTest { public void getCarConnectionSummary_singleProfileActiveDeviceHearingAid() { // Test without battery level // Set Hearing Aid profile to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set device as Active for Hearing Aid and test connection state summary @@ -414,8 +415,7 @@ public class CachedBluetoothDeviceTest { // Set Hearing Aid profile to be disconnected and test connection state summary mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID); - mCachedDevice.onProfileStateChanged(mHearingAidProfile, - BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @@ -423,8 +423,8 @@ public class CachedBluetoothDeviceTest { public void getCarConnectionSummary_multipleProfilesActiveDevice() { // Test without battery level // Set A2DP and HFP profiles to be connected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); // Set device as Active for A2DP and HFP and test connection state summary @@ -439,14 +439,14 @@ public class CachedBluetoothDeviceTest { // Disconnect A2DP only and test connection state summary mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( "Connected (no media), battery 10%, active (phone)"); // Disconnect HFP only and test connection state summary mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( "Connected (no phone), battery 10%, active (media)"); @@ -454,21 +454,21 @@ public class CachedBluetoothDeviceTest { // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; // Set A2DP and HFP profiles to be connected, Active and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active"); // Set A2DP and HFP profiles to be disconnected and test connection state summary - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.getCarConnectionSummary()).isNull(); } @Test - public void testDeviceName_testAliasNameAvailable() { + public void deviceName_testAliasNameAvailable() { when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS); when(mDevice.getName()).thenReturn(DEVICE_NAME); CachedBluetoothDevice cachedBluetoothDevice = @@ -480,7 +480,7 @@ public class CachedBluetoothDeviceTest { } @Test - public void testDeviceName_testNameNotAvailable() { + public void deviceName_testNameNotAvailable() { CachedBluetoothDevice cachedBluetoothDevice = new CachedBluetoothDevice(mContext, mProfileManager, mDevice); // Verify device address is returned on getName @@ -490,7 +490,7 @@ public class CachedBluetoothDeviceTest { } @Test - public void testDeviceName_testRenameDevice() { + public void deviceName_testRenameDevice() { final String[] alias = {DEVICE_ALIAS}; doAnswer(invocation -> alias[0]).when(mDevice).getAliasName(); doAnswer(invocation -> { @@ -513,7 +513,7 @@ public class CachedBluetoothDeviceTest { } @Test - public void testSetActive() { + public void setActive() { when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile); when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true); @@ -521,19 +521,19 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.setActive()).isFalse(); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.setActive()).isTrue(); - mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED); + updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); assertThat(mCachedDevice.setActive()).isTrue(); - mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); + updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); assertThat(mCachedDevice.setActive()).isFalse(); } @Test - public void testIsA2dpDevice_isA2dpDevice() { + public void isA2dpDevice_isA2dpDevice() { when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); when(mA2dpProfile.getConnectionStatus(mDevice)). thenReturn(BluetoothProfile.STATE_CONNECTED); @@ -542,7 +542,7 @@ public class CachedBluetoothDeviceTest { } @Test - public void testIsA2dpDevice_isNotA2dpDevice() { + public void isA2dpDevice_isNotA2dpDevice() { when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); when(mA2dpProfile.getConnectionStatus(mDevice)). thenReturn(BluetoothProfile.STATE_DISCONNECTING); @@ -551,7 +551,7 @@ public class CachedBluetoothDeviceTest { } @Test - public void testIsHfpDevice_isHfpDevice() { + public void isHfpDevice_isHfpDevice() { when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile); when(mHfpProfile.getConnectionStatus(mDevice)). thenReturn(BluetoothProfile.STATE_CONNECTED); @@ -637,4 +637,24 @@ public class CachedBluetoothDeviceTest { verify(mDevice, never()).setAlias(any()); } + + @Test + public void getProfileConnectionState_nullProfile_returnDisconnected() { + assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo( + BluetoothProfile.STATE_DISCONNECTED); + } + + @Test + public void getProfileConnectionState_profileConnected_returnConnected() { + doReturn(BluetoothProfile.STATE_CONNECTED).when(mA2dpProfile).getConnectionStatus( + any(BluetoothDevice.class)); + + assertThat(mCachedDevice.getProfileConnectionState(mA2dpProfile)).isEqualTo( + BluetoothProfile.STATE_CONNECTED); + } + + private void updateProfileStatus(LocalBluetoothProfile profile, int status) { + doReturn(status).when(profile).getConnectionStatus(mDevice); + mCachedDevice.onProfileStateChanged(profile, status); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java index c23ad79a52fe..887c1d57c870 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java @@ -38,13 +38,13 @@ import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu; import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; -import com.android.settingslib.testutils.FragmentTestUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.android.controller.ActivityController; +import org.robolectric.shadows.androidx.fragment.FragmentController; @RunWith(SettingsLibRobolectricTestRunner.class) public class LifecycleTest { @@ -184,7 +184,7 @@ public class LifecycleTest { @Test public void runThroughDialogFragmentLifecycles_shouldObserveEverything() { final TestDialogFragment fragment = new TestDialogFragment(); - FragmentTestUtils.startFragment(fragment); + FragmentController.setupFragment(fragment); fragment.onCreateOptionsMenu(null, null); fragment.onPrepareOptionsMenu(null); @@ -208,7 +208,7 @@ public class LifecycleTest { @Test public void runThroughFragmentLifecycles_shouldObserveEverything() { final TestFragment fragment = new TestFragment(); - FragmentTestUtils.startFragment(fragment); + FragmentController.setupFragment(fragment); fragment.onCreateOptionsMenu(null, null); fragment.onPrepareOptionsMenu(null); @@ -248,7 +248,7 @@ public class LifecycleTest { @Test public void onOptionItemSelectedShortCircuitsIfAnObserverHandlesTheMenuItem() { final TestFragment fragment = new TestFragment(); - FragmentTestUtils.startFragment(fragment); + FragmentController.setupFragment(fragment); final OptionItemAccepter accepter = new OptionItemAccepter(); fragment.getLifecycle().addObserver(accepter); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index b04d04717be5..c7910f97675e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -342,6 +342,20 @@ public class ActivityManagerWrapper { } /** + * Moves an already resumed task to the side of the screen to initiate split screen. + */ + public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, + Rect initialBounds) { + try { + return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId, + createMode, true /* onTop */, false /* animate */, initialBounds, + true /* showRecents */); + } catch (RemoteException e) { + return false; + } + } + + /** * Registers a task stack listener with the system. * This should be called on the main thread. */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index d83b36d6ea80..3191d14c5a83 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -151,6 +151,25 @@ public class WindowManagerWrapper { } } + public void setPipVisibility(final boolean visible) { + try { + WindowManagerGlobal.getWindowManagerService().setPipVisibility(visible); + } catch (RemoteException e) { + Log.e(TAG, "Unable to reach window manager", e); + } + } + + /** + * @return whether there is a soft nav bar. + */ + public boolean hasSoftNavigationBar() { + try { + return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(); + } catch (RemoteException e) { + return false; + } + } + /** * @return The side of the screen where navigation bar is positioned. * @see #NAV_BAR_POS_RIGHT diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index b159b393862a..b8df3c067969 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -342,12 +342,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe case SimPuk: // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); - if (securityMode != SecurityMode.None - || !mLockPatternUtils.isLockScreenDisabled( + if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled( KeyguardUpdateMonitor.getCurrentUser())) { - showSecurityScreen(securityMode); - } else { finish = true; + } else { + showSecurityScreen(securityMode); } break; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 10c8ec09bd5b..f1b53fec0714 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -86,9 +86,8 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.WirelessUtils; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; - +import com.android.systemui.shared.system.TaskStackChangeListener; import com.google.android.collect.Lists; import java.io.FileDescriptor; @@ -2218,8 +2217,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } - private final SysUiTaskStackChangeListener - mTaskStackListener = new SysUiTaskStackChangeListener() { + private final TaskStackChangeListener + mTaskStackListener = new TaskStackChangeListener() { @Override public void onTaskStackChangedBackground() { try { diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index bd2b7a577b3d..1af2156c4bbe 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -16,6 +16,11 @@ package com.android.systemui; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; +import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; +import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; + import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -33,11 +38,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.view.MotionEvent; - import com.android.systemui.OverviewProxyService.OverviewProxyListener; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -46,17 +47,11 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.CallbackController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; - import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; -import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; - /** * Class to send information from overview to launcher with a binder. */ @@ -133,7 +128,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } long token = Binder.clearCallingIdentity(); try { - EventBus.getDefault().post(new DockedFirstAnimationFrameEvent()); + Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class); + if (divider != null) { + divider.onDockedFirstAnimationFrame(); + } } finally { Binder.restoreCallingIdentity(token); } @@ -314,8 +312,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis getDefaultInteractionFlags()); // Listen for the package update changes. - if (SystemServicesProxy.getInstance(context) - .isSystemUser(mDeviceProvisionedController.getCurrentUser())) { + if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) { updateEnabledState(); mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback); IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index f9dbf4a15e5c..fb343f9b9b45 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -22,27 +22,10 @@ import android.view.View; public interface RecentsComponent { void showRecentApps(boolean triggeredFromAltTab); - void showNextAffiliatedTask(); - void showPrevAffiliatedTask(); /** * Docks the top-most task and opens recents. */ - boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds, + boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction); - - /** - * Called during a drag-from-navbar-in gesture. - * - * @param distanceFromTop the distance of the current drag in gesture from the top of the - * screen - */ - void onDraggingInRecents(float distanceFromTop); - - /** - * Called when the gesture to drag in recents ended. - * - * @param velocity the velocity of the finger when releasing it in pixels per second - */ - void onDraggingInRecentsEnded(float velocity); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java index 745f312a29b4..d833c16c04b3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java @@ -19,9 +19,6 @@ package com.android.systemui.keyguard; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; - import java.util.ArrayList; /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java index 0cedf9825990..74f770679cc9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java @@ -19,7 +19,6 @@ package com.android.systemui.keyguard; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; -import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.app.KeyguardManager; import android.content.ComponentName; @@ -29,11 +28,9 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; - import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; public class WorkLockActivityController { private static final String TAG = WorkLockActivityController.class.getSimpleName(); @@ -111,7 +108,7 @@ public class WorkLockActivityController { } } - private final SysUiTaskStackChangeListener mLockListener = new SysUiTaskStackChangeListener() { + private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() { @Override public void onTaskProfileLocked(int taskId, int userId) { startWorkChallengeInTask(taskId, userId); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java index b7164cbb3271..864a6f9185fa 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java @@ -21,11 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import android.content.pm.PackageManager; import android.content.res.Configuration; - +import android.os.UserHandle; +import android.os.UserManager; import com.android.systemui.SystemUI; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.component.ExpandPipEvent; import com.android.systemui.statusbar.CommandQueue; - import java.io.FileDescriptor; import java.io.PrintWriter; @@ -47,8 +48,8 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks { } // Ensure that we are the primary user's SystemUI. - final int processUser = SystemServicesProxy.getInstance(mContext).getProcessUser(); - if (!SystemServicesProxy.getInstance(mContext).isSystemUser(processUser)) { + final int processUser = UserManager.get(mContext).getUserHandle(); + if (processUser != UserHandle.USER_SYSTEM) { throw new IllegalStateException("Non-primary Pip component not currently supported."); } @@ -58,6 +59,7 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks { mPipManager.initialize(mContext); getComponent(CommandQueue.class).addCallbacks(this); + putComponent(PipUI.class, this); } @Override @@ -65,6 +67,10 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks { mPipManager.showPictureInPictureMenu(); } + public void expandPip() { + EventBus.getDefault().send(new ExpandPipEvent()); + } + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java index 784ac4e16838..9bf46bb488f3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.recents.misc; +package com.android.systemui.pip.phone; import android.os.Handler; import android.os.HandlerThread; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java index 5547e2d3985d..9ce2606a2a15 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java @@ -19,21 +19,17 @@ package com.android.systemui.pip.phone; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; - import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.WindowManagerWrapper; public class PipDismissViewController { @@ -59,7 +55,7 @@ public class PipDismissViewController { if (mDismissView == null) { // Determine sizes for the view final Rect stableInsets = new Rect(); - SystemServicesProxy.getInstance(mContext).getStableInsets(stableInsets); + WindowManagerWrapper.getInstance().getStableInsets(stableInsets); final Point windowSize = new Point(); mWindowManager.getDefaultDisplay().getRealSize(windowSize); final int gradientHeight = mContext.getResources().getDimensionPixelSize( 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 ee15655d87b2..04746c16585a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -17,7 +17,6 @@ package com.android.systemui.pip.phone; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManager.INPUT_CONSUMER_PIP; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -36,15 +35,15 @@ import android.view.IPinnedStackController; import android.view.IPinnedStackListener; import android.view.IWindowManager; import android.view.WindowManagerGlobal; - +import com.android.systemui.Dependency; +import com.android.systemui.UiOffloadThread; import com.android.systemui.pip.BasePipManager; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.component.ExpandPipEvent; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; - +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.WindowManagerWrapper; import java.io.PrintWriter; /** @@ -72,7 +71,7 @@ public class PipManager implements BasePipManager { /** * Handler for system task stack changes. */ - SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() { + TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { @Override public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { mTouchHandler.onActivityPinned(); @@ -80,7 +79,9 @@ public class PipManager implements BasePipManager { mMenuController.onActivityPinned(); mAppOpsListener.onActivityPinned(packageName); - SystemServicesProxy.getInstance(mContext).setPipVisibility(true); + Dependency.get(UiOffloadThread.class).submit(() -> { + WindowManagerWrapper.getInstance().setPipVisibility(true); + }); } @Override @@ -93,7 +94,9 @@ public class PipManager implements BasePipManager { mTouchHandler.onActivityUnpinned(topActivity); mAppOpsListener.onActivityUnpinned(); - SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null); + Dependency.get(UiOffloadThread.class).submit(() -> { + WindowManagerWrapper.getInstance().setPipVisibility(topActivity != null); + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index f0ab046f7dbe..ce7da79de794 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -30,7 +30,6 @@ import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.ActivityManager.StackInfo; -import android.app.ActivityTaskManager; import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.content.Context; @@ -43,14 +42,11 @@ import android.os.Message; import android.os.RemoteException; import android.util.Log; import android.view.animation.Interpolator; - import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.os.SomeArgs; import com.android.internal.policy.PipSnapAlgorithm; -import com.android.systemui.recents.misc.ForegroundThread; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.FlingAnimationUtils; - import java.io.PrintWriter; /** @@ -116,7 +112,7 @@ public class PipMotionHelper implements Handler.Callback { */ void onConfigurationChanged() { mSnapAlgorithm.onConfigurationChanged(); - SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); + WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); } /** 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 020c5500c0a0..43e9db7f0ee5 100755 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -16,6 +16,11 @@ package com.android.systemui.pip.tv; +import static android.app.ActivityTaskManager.INVALID_STACK_ID; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.view.Display.DEFAULT_DISPLAY; + import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; @@ -44,22 +49,17 @@ import android.view.IPinnedStackController; import android.view.IPinnedStackListener; import android.view.IWindowManager; import android.view.WindowManagerGlobal; - +import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.UiOffloadThread; import com.android.systemui.pip.BasePipManager; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; - +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.WindowManagerWrapper; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.view.Display.DEFAULT_DISPLAY; - /** * Manages the picture-in-picture (PIP) UI and states. */ @@ -630,7 +630,7 @@ public class PipManager implements BasePipManager { return false; } - private SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() { + private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { @Override public void onTaskStackChanged() { if (DEBUG) Log.d(TAG, "onTaskStackChanged()"); @@ -754,7 +754,9 @@ public class PipManager implements BasePipManager { } private void updatePipVisibility(final boolean visible) { - SystemServicesProxy.getInstance(mContext).setPipVisibility(visible); + Dependency.get(UiOffloadThread.class).submit(() -> { + WindowManagerWrapper.getInstance().setPipVisibility(visible); + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index c36cdf6ac262..b0d95982d989 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -365,7 +365,11 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks { .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - getView().animate().setListener(null); + if (getView() != null) { + // The view could be destroyed before the animation completes when + // switching users. + getView().animate().setListener(null); + } mHeaderAnimating = false; updateQsState(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl index fc1831d55c9d..90c10992bc94 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl +++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl @@ -31,8 +31,7 @@ oneway interface IRecentsNonSystemUserCallbacks { void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); void toggleRecents(int recentsGrowTarget); void onConfigurationChanged(); - void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode, - in Rect initialBounds); + void splitPrimaryTask(int topTaskId, int stackCreateMode, in Rect initialBounds); void onDraggingInRecents(float distanceFromTop); void onDraggingInRecentsEnded(float velocity); void showCurrentUserToast(int msgResId, int msgLength); diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl index 58d8d8fd600a..e97714486dcf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl +++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl @@ -29,7 +29,7 @@ oneway interface IRecentsSystemUserCallbacks { void updateRecentsVisibility(boolean visible); void startScreenPinning(int taskId); void sendRecentsDrawnEvent(); - void sendDockingTopTaskEvent(int dragMode, in Rect initialRect); + void sendDockingTopTaskEvent(in Rect initialRect); void sendLaunchRecentsEvent(); void sendDockedFirstAnimationFrameEvent(); void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 8bb3c0231a76..74f6c2dec4e7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -53,6 +53,7 @@ import com.android.systemui.OverviewProxyService; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SystemUIApplication; +import com.android.systemui.recents.events.ui.RecentsGrowingEvent; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.SystemUI; import com.android.systemui.recents.events.EventBus; @@ -248,6 +249,10 @@ public class Recents extends SystemUI mImpl.onBootCompleted(); } + public void growRecents() { + EventBus.getDefault().send(new RecentsGrowingEvent()); + } + /** * Shows the Recents. */ @@ -463,7 +468,7 @@ public class Recents extends SystemUI } @Override - public boolean splitPrimaryTask(int dragMode, int stackCreateMode, Rect initialBounds, + public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction) { // Ensure the device has been provisioned before allowing the user to interact with // recents @@ -495,16 +500,15 @@ public class Recents extends SystemUI runningTask.topActivity.flattenToShortString()); } if (sSystemServicesProxy.isSystemUser(currentUser)) { - mImpl.splitPrimaryTask(runningTask.id, dragMode, stackCreateMode, - initialBounds); + mImpl.splitPrimaryTask(runningTask.id, stackCreateMode, initialBounds); } else { if (mSystemToUserCallbacks != null) { IRecentsNonSystemUserCallbacks callbacks = mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser); if (callbacks != null) { try { - callbacks.splitPrimaryTask(runningTask.id, dragMode, - stackCreateMode, initialBounds); + callbacks.splitPrimaryTask(runningTask.id, stackCreateMode, + initialBounds); } catch (RemoteException e) { Log.e(TAG, "Callback failed", e); } @@ -552,53 +556,6 @@ public class Recents extends SystemUI } } - @Override - public void onDraggingInRecents(float distanceFromTop) { - if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) { - mImpl.onDraggingInRecents(distanceFromTop); - } else { - if (mSystemToUserCallbacks != null) { - IRecentsNonSystemUserCallbacks callbacks = - mSystemToUserCallbacks.getNonSystemUserRecentsForUser( - mDraggingInRecentsCurrentUser); - if (callbacks != null) { - try { - callbacks.onDraggingInRecents(distanceFromTop); - } catch (RemoteException e) { - Log.e(TAG, "Callback failed", e); - } - } else { - Log.e(TAG, "No SystemUI callbacks found for user: " - + mDraggingInRecentsCurrentUser); - } - } - } - } - - @Override - public void onDraggingInRecentsEnded(float velocity) { - if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) { - mImpl.onDraggingInRecentsEnded(velocity); - } else { - if (mSystemToUserCallbacks != null) { - IRecentsNonSystemUserCallbacks callbacks = - mSystemToUserCallbacks.getNonSystemUserRecentsForUser( - mDraggingInRecentsCurrentUser); - if (callbacks != null) { - try { - callbacks.onDraggingInRecentsEnded(velocity); - } catch (RemoteException e) { - Log.e(TAG, "Callback failed", e); - } - } else { - Log.e(TAG, "No SystemUI callbacks found for user: " - + mDraggingInRecentsCurrentUser); - } - } - } - } - - @Override public void showNextAffiliatedTask() { // Ensure the device has been provisioned before allowing the user to interact with // recents @@ -609,7 +566,6 @@ public class Recents extends SystemUI mImpl.showNextAffiliatedTask(); } - @Override public void showPrevAffiliatedTask() { // Ensure the device has been provisioned before allowing the user to interact with // recents @@ -686,7 +642,12 @@ public class Recents extends SystemUI public final void onBusEvent(DockedFirstAnimationFrameEvent event) { SystemServicesProxy ssp = Recents.getSystemServices(); int processUser = ssp.getProcessUser(); - if (!ssp.isSystemUser(processUser)) { + if (ssp.isSystemUser(processUser)) { + final Divider divider = getComponent(Divider.class); + if (divider != null) { + divider.onDockedFirstAnimationFrame(); + } + } else { postToSystemUser(new Runnable() { @Override public void run() { @@ -723,7 +684,12 @@ public class Recents extends SystemUI public final void onBusEvent(final RecentsDrawnEvent event) { int processUser = sSystemServicesProxy.getProcessUser(); - if (!sSystemServicesProxy.isSystemUser(processUser)) { + if (sSystemServicesProxy.isSystemUser(processUser)) { + final Divider divider = getComponent(Divider.class); + if (divider != null) { + divider.onRecentsDrawn(); + } + } else { postToSystemUser(new Runnable() { @Override public void run() { @@ -739,13 +705,17 @@ public class Recents extends SystemUI public final void onBusEvent(final DockedTopTaskEvent event) { int processUser = sSystemServicesProxy.getProcessUser(); - if (!sSystemServicesProxy.isSystemUser(processUser)) { + if (sSystemServicesProxy.isSystemUser(processUser)) { + final Divider divider = getComponent(Divider.class); + if (divider != null) { + divider.onDockedTopTask(); + } + } else { postToSystemUser(new Runnable() { @Override public void run() { try { - mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode, - event.initialRect); + mUserToSystemCallbacks.sendDockingTopTaskEvent(event.initialRect); } catch (RemoteException e) { Log.e(TAG, "Callback failed", e); } @@ -756,7 +726,12 @@ public class Recents extends SystemUI public final void onBusEvent(final RecentsActivityStartingEvent event) { int processUser = sSystemServicesProxy.getProcessUser(); - if (!sSystemServicesProxy.isSystemUser(processUser)) { + if (sSystemServicesProxy.isSystemUser(processUser)) { + final Divider divider = getComponent(Divider.class); + if (divider != null) { + divider.onRecentsActivityStarting(); + } + } else { postToSystemUser(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 63a65d030f6d..d95c7313a282 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -49,6 +49,7 @@ import android.widget.Toast; import com.android.systemui.Dependency; import com.android.systemui.OverviewProxyService; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.pip.phone.ForegroundThread; import com.google.android.collect.Lists; import com.android.internal.logging.MetricsLogger; @@ -72,7 +73,6 @@ import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; import com.android.systemui.recents.events.ui.DraggingInRecentsEvent; import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent; import com.android.systemui.recents.misc.DozeTrigger; -import com.android.systemui.recents.misc.ForegroundThread; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; @@ -690,14 +690,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener showRelativeAffiliatedTask(false); } - public void splitPrimaryTask(int taskId, int dragMode, int stackCreateMode, - Rect initialBounds) { + public void splitPrimaryTask(int taskId, int stackCreateMode, Rect initialBounds) { SystemServicesProxy ssp = Recents.getSystemServices(); // Make sure we inform DividerView before we actually start the activity so we can change // the resize mode already. if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) { - EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds)); + EventBus.getDefault().send(new DockedTopTaskEvent(initialBounds)); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java index beec4b395e9c..a1da785f2a80 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java @@ -87,12 +87,11 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub { } @Override - public void splitPrimaryTask(int topTaskId, int dragMode, int stackCreateMode, - Rect initialBounds) throws RemoteException { + public void splitPrimaryTask(int topTaskId, int stackCreateMode, Rect initialBounds) + throws RemoteException { SomeArgs args = SomeArgs.obtain(); args.argi1 = topTaskId; - args.argi2 = dragMode; - args.argi3 = stackCreateMode; + args.argi2 = stackCreateMode; args.arg1 = initialBounds; mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args)); } @@ -141,7 +140,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub { break; case MSG_DOCK_TOP_TASK: args = (SomeArgs) msg.obj; - mImpl.splitPrimaryTask(args.argi1, args.argi2, args.argi3 = 0, + mImpl.splitPrimaryTask(args.argi1, args.argi2 = 0, (Rect) args.arg1); break; case MSG_ON_DRAGGING_IN_RECENTS: diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java index ff1f7dc5a2a8..c5e9f046aa16 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java @@ -26,13 +26,13 @@ import android.util.SparseArray; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; +import com.android.systemui.pip.phone.ForegroundThread; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; import com.android.systemui.recents.events.activity.DockedTopTaskEvent; import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent; import com.android.systemui.recents.events.ui.RecentsDrawnEvent; -import com.android.systemui.recents.misc.ForegroundThread; /** * An implementation of the system user's Recents interface to be called remotely by secondary @@ -99,8 +99,8 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub { } @Override - public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException { - EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect)); + public void sendDockingTopTaskEvent(Rect initialRect) throws RemoteException { + EventBus.getDefault().post(new DockedTopTaskEvent(initialRect)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java index f1bc214670f5..9e3ced3f3757 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java @@ -26,11 +26,9 @@ import com.android.systemui.recents.events.EventBus; */ public class DockedTopTaskEvent extends EventBus.Event { - public int dragMode; public Rect initialRect; - public DockedTopTaskEvent(int dragMode, Rect initialRect) { - this.dragMode = dragMode; + public DockedTopTaskEvent(Rect initialRect) { this.initialRect = initialRect; } } diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 750002cbc5ca..64fa8f86c5f6 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -18,11 +18,7 @@ package com.android.systemui.shortcut; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -import static android.os.UserHandle.USER_CURRENT; -import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE; - -import android.app.ActivityManager; import android.content.res.Configuration; import android.os.RemoteException; import android.util.Log; @@ -30,17 +26,11 @@ import android.view.IWindowManager; import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; - import com.android.internal.policy.DividerSnapAlgorithm; import com.android.systemui.SystemUI; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.stackdivider.DividerView; -import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; - -import java.util.List; /** * Dispatches shortcut to System UI components @@ -94,7 +84,7 @@ public class ShortcutKeyDispatcher extends SystemUI if (dockSide == WindowManager.DOCKED_INVALID) { // Split the screen Recents recents = getComponent(Recents.class); - recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT) + recents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT) ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1); } else { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index da0a43551f1f..ea194a70adf2 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -16,29 +16,28 @@ package com.android.systemui.stackdivider; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; + import android.content.res.Configuration; import android.os.RemoteException; +import android.util.Log; import android.view.IDockedStackListener; import android.view.LayoutInflater; import android.view.View; - +import android.view.WindowManagerGlobal; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.ui.RecentsDrawnEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; - -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - import java.io.FileDescriptor; import java.io.PrintWriter; /** * Controls the docked stack divider. */ -public class Divider extends SystemUI { +public class Divider extends SystemUI implements DividerView.DividerCallbacks { + private static final String TAG = "Divider"; + private DividerWindowManager mWindowManager; private DividerView mView; private final DividerState mDividerState = new DividerState(); @@ -55,10 +54,13 @@ public class Divider extends SystemUI { update(mContext.getResources().getConfiguration()); putComponent(Divider.class, this); mDockDividerVisibilityListener = new DockDividerVisibilityListener(); - SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.registerDockedStackListener(mDockDividerVisibilityListener); + try { + WindowManagerGlobal.getWindowManagerService().registerDockedStackListener( + mDockDividerVisibilityListener); + } catch (Exception e) { + Log.e(TAG, "Failed to register docked stack listener", e); + } mForcedResizableController = new ForcedResizableInfoActivityController(mContext); - EventBus.getDefault().register(this); } @Override @@ -82,7 +84,7 @@ public class Divider extends SystemUI { private void addDivider(Configuration configuration) { mView = (DividerView) LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null); - mView.injectDependencies(mWindowManager, mDividerState); + mView.injectDependencies(mWindowManager, mDividerState, this); mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE); mView.setMinimizedDockStack(mMinimized, mHomeStackResizable); final int size = mContext.getResources().getDimensionPixelSize( @@ -156,18 +158,64 @@ public class Divider extends SystemUI { mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme); } + public void onRecentsActivityStarting() { + if (mView != null) { + mView.onRecentsActivityStarting(); + } + } + /** - * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a + * Workaround for b/62528361, at the time recents has drawn, it may happen before a * configuration change to the Divider, and internally, the event will be posted to the * subscriber, or DividerView, which has been removed and prevented from resizing. Instead, * register the event handler here and proxy the event to the current DividerView. */ - public final void onBusEvent(RecentsDrawnEvent drawnEvent) { + public void onRecentsDrawn() { if (mView != null) { mView.onRecentsDrawn(); } } + public void onUndockingTask() { + if (mView != null) { + mView.onUndockingTask(); + } + } + + public void onDockedFirstAnimationFrame() { + if (mView != null) { + mView.onDockedFirstAnimationFrame(); + } + } + + public void onDockedTopTask() { + if (mView != null) { + mView.onDockedTopTask(); + } + } + + public void onAppTransitionFinished() { + mForcedResizableController.onAppTransitionFinished(); + } + + @Override + public void onDraggingStart() { + mForcedResizableController.onDraggingStart(); + } + + @Override + public void onDraggingEnd() { + mForcedResizableController.onDraggingEnd(); + } + + @Override + public void growRecents() { + Recents recents = getComponent(Recents.class); + if (recents != null) { + recents.growRecents(); + } + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(" mVisible="); pw.println(mVisible); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 98925b9ba9e5..fa01af68364e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -55,7 +55,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.widget.FrameLayout; - import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; @@ -64,17 +63,8 @@ import com.android.internal.policy.DockedDividerUtils; import com.android.internal.view.SurfaceFlingerVsyncChoreographer; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; -import com.android.systemui.recents.events.activity.DockedTopTaskEvent; -import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; -import com.android.systemui.recents.events.activity.UndockingTaskEvent; -import com.android.systemui.recents.events.ui.RecentsGrowingEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.stackdivider.events.StartedDragingEvent; -import com.android.systemui.stackdivider.events.StoppedDragingEvent; +import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.FlingAnimationUtils; -import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; /** * Docked stack divider. @@ -82,6 +72,12 @@ import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; public class DividerView extends FrameLayout implements OnTouchListener, OnComputeInternalInsetsListener { + public interface DividerCallbacks { + void onDraggingStart(); + void onDraggingEnd(); + void growRecents(); + } + static final long TOUCH_ANIMATION_DURATION = 150; static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; @@ -149,6 +145,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private FlingAnimationUtils mFlingAnimationUtils; private DividerSnapAlgorithm mSnapAlgorithm; private DividerSnapAlgorithm mMinimizedSnapAlgorithm; + private DividerCallbacks mCallback; private final Rect mStableInsets = new Rect(); private boolean mGrowRecents; @@ -162,6 +159,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private DividerState mState; private final SurfaceFlingerVsyncChoreographer mSfChoreographer; + // The view is removed or in the process of been removed from the system. private boolean mRemoved; @@ -306,7 +304,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - EventBus.getDefault().register(this); // Save the current target if not minimized once attached to window if (mHomeStackResizable && mDockSide != WindowManager.DOCKED_INVALID @@ -315,14 +312,9 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - EventBus.getDefault().unregister(this); - } - void onDividerRemoved() { mRemoved = true; + mCallback = null; mHandler.removeMessages(MSG_RESIZE_STACK); } @@ -364,13 +356,15 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } - public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState) { + public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState, + DividerCallbacks callback) { mWindowManager = windowManager; mState = dividerState; + mCallback = callback; // Set the previous position ratio before minimized state after attaching this divider if (mStableInsets.isEmpty()) { - SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); + WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); } if (mState.mRatioPositionBeforeMinimized == 0) { @@ -419,7 +413,9 @@ public class DividerView extends FrameLayout implements OnTouchListener, mWindowManager.setSlippery(false); liftBackground(); } - EventBus.getDefault().send(new StartedDragingEvent()); + if (mCallback != null) { + mCallback.onDraggingStart(); + } return mDockSide != WindowManager.DOCKED_INVALID; } @@ -617,7 +613,9 @@ public class DividerView extends FrameLayout implements OnTouchListener, mCurrentAnimator = null; mEntranceAnimationRunning = false; mExitAnimationRunning = false; - EventBus.getDefault().send(new StoppedDragingEvent()); + if (mCallback != null) { + mCallback.onDraggingEnd(); + } // Record last snap target the divider moved to if (mHomeStackResizable && !mIsInMinimizeInteraction) { @@ -776,7 +774,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mDisplayRotation != mDefaultDisplay.getRotation()) { // Splitscreen to minimize is about to starts after rotating landscape to seascape, // update insets, display info and snap algorithm targets - SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); + WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); repositionSnapTargetBeforeMinimized(); updateDisplayInfo(); } else { @@ -910,7 +908,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, requestLayout(); // Update the snap position to the new docked side with correct insets - SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); + WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); mMinimizedSnapAlgorithm = null; initializeSnapAlgorithm(); @@ -1271,7 +1269,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } - public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) { + void onRecentsActivityStarting() { if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget() && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) { @@ -1280,16 +1278,14 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } - public final void onBusEvent(DockedFirstAnimationFrameEvent event) { + void onDockedFirstAnimationFrame() { saveSnapTargetBeforeMinimized(mSnapAlgorithm.getMiddleTarget()); } - public final void onBusEvent(DockedTopTaskEvent event) { - if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) { - mState.growAfterRecentsDrawn = false; - mState.animateAfterRecentsDrawn = true; - startDragging(false /* animate */, false /* touching */); - } + void onDockedTopTask() { + mState.growAfterRecentsDrawn = false; + mState.animateAfterRecentsDrawn = true; + startDragging(false /* animate */, false /* touching */); updateDockSide(); mEntranceAnimationRunning = true; @@ -1297,7 +1293,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mSnapAlgorithm.getMiddleTarget()); } - public void onRecentsDrawn() { + void onRecentsDrawn() { updateDockSide(); final int position = calculatePositionForInsetBounds(); if (mState.animateAfterRecentsDrawn) { @@ -1314,13 +1310,15 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mState.growAfterRecentsDrawn) { mState.growAfterRecentsDrawn = false; updateDockSide(); - EventBus.getDefault().send(new RecentsGrowingEvent()); + if (mCallback != null) { + mCallback.growRecents(); + } stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336, Interpolators.FAST_OUT_SLOW_IN); } } - public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) { + void onUndockingTask() { int dockSide = mWindowManagerProxy.getDockSide(); if (dockSide != WindowManager.DOCKED_INVALID && (mHomeStackResizable || !mDockedStackMinimized)) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java index 4415bd7a631b..02f75050c061 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java @@ -52,7 +52,7 @@ public class ForcedResizableInfoActivity extends Activity implements OnTouchList protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.forced_resizable_activity); - TextView tv = (TextView) findViewById(com.android.internal.R.id.message); + TextView tv = findViewById(com.android.internal.R.id.message); int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1); String text; switch (reason) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java index 826fa6cefccc..f66db48f441c 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java @@ -16,8 +16,7 @@ package com.android.systemui.stackdivider; -import static com.android.systemui.stackdivider.ForcedResizableInfoActivity - .EXTRA_FORCED_RESIZEABLE_REASON; +import static com.android.systemui.stackdivider.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON; import android.app.ActivityOptions; import android.content.Context; @@ -26,16 +25,9 @@ import android.os.Handler; import android.os.UserHandle; import android.util.ArraySet; import android.widget.Toast; - import com.android.systemui.R; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; -import com.android.systemui.recents.events.component.ShowUserToastEvent; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.stackdivider.events.StartedDragingEvent; -import com.android.systemui.stackdivider.events.StoppedDragingEvent; +import com.android.systemui.shared.system.TaskStackChangeListener; /** * Controller that decides when to show the {@link ForcedResizableInfoActivity}. @@ -49,7 +41,7 @@ public class ForcedResizableInfoActivityController { private final Handler mHandler = new Handler(); private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>(); private final ArraySet<String> mPackagesShownInSession = new ArraySet<>(); - private boolean mDividerDraging; + private boolean mDividerDragging; private final Runnable mTimeoutRunnable = new Runnable() { @Override @@ -75,9 +67,8 @@ public class ForcedResizableInfoActivityController { public ForcedResizableInfoActivityController(Context context) { mContext = context; - EventBus.getDefault().register(this); ActivityManagerWrapper.getInstance().registerTaskStackListener( - new SysUiTaskStackChangeListener() { + new TaskStackChangeListener() { @Override public void onActivityForcedResizable(String packageName, int taskId, int reason) { @@ -102,19 +93,19 @@ public class ForcedResizableInfoActivityController { } } - public final void onBusEvent(AppTransitionFinishedEvent event) { - if (!mDividerDraging) { + public void onAppTransitionFinished() { + if (!mDividerDragging) { showPending(); } } - public final void onBusEvent(StartedDragingEvent event) { - mDividerDraging = true; + void onDraggingStart() { + mDividerDragging = true; mHandler.removeCallbacks(mTimeoutRunnable); } - public final void onBusEvent(StoppedDragingEvent event) { - mDividerDraging = false; + void onDraggingEnd() { + mDividerDragging = false; showPending(); } @@ -127,13 +118,13 @@ public class ForcedResizableInfoActivityController { } private void activityDismissingDockedStack() { - EventBus.getDefault().send(new ShowUserToastEvent( - R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT)); + Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, + Toast.LENGTH_SHORT).show(); } private void activityLaunchOnSecondaryDisplayFailed() { - EventBus.getDefault().send(new ShowUserToastEvent( - R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT)); + Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text, + Toast.LENGTH_SHORT).show(); } private void showPending() { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java deleted file mode 100644 index 5d1985123b32..000000000000 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java +++ /dev/null @@ -1,25 +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 com.android.systemui.stackdivider.events; - -import com.android.systemui.recents.events.EventBus; - -/** - * Sent when the divider is being draged either manually or by an animation. - */ -public class StartedDragingEvent extends EventBus.Event { -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 247e3d342bbb..00e0b954d7be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -16,6 +16,10 @@ package com.android.systemui.statusbar; +import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlertDialog; @@ -30,10 +34,10 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.content.res.ColorStateList; -import android.graphics.drawable.Icon; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.hardware.input.InputManager; import android.os.Handler; import android.os.Looper; @@ -51,29 +55,23 @@ import android.view.View; import android.view.View.AccessibilityDelegate; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowManager; import android.view.WindowManager.KeyboardShortcutsReceiver; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; - import com.android.internal.app.AssistUtils; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.settingslib.Utils; import com.android.systemui.R; -import com.android.systemui.recents.misc.SystemServicesProxy; - import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import static android.content.Context.LAYOUT_INFLATER_SERVICE; -import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; -import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; - /** * Contains functionality for handling keyboard shortcuts. */ @@ -372,19 +370,19 @@ public final class KeyboardShortcuts { private void showKeyboardShortcuts(int deviceId) { retrieveKeyCharacterMap(deviceId); - SystemServicesProxy.getInstance(mContext).requestKeyboardShortcuts(mContext, - new KeyboardShortcutsReceiver() { - @Override - public void onKeyboardShortcutsReceived( - final List<KeyboardShortcutGroup> result) { - result.add(getSystemShortcuts()); - final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts(); - if (appShortcuts != null) { - result.add(appShortcuts); - } - showKeyboardShortcutsDialog(result); - } - }, deviceId); + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() { + @Override + public void onKeyboardShortcutsReceived( + final List<KeyboardShortcutGroup> result) { + result.add(getSystemShortcuts()); + final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts(); + if (appShortcuts != null) { + result.add(appShortcuts); + } + showKeyboardShortcutsDialog(result); + } + }, deviceId); } private void dismissKeyboardShortcuts() { 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 304a00fbba4a..2450e448c4f7 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.ActivityTaskManager; -import android.car.user.CarUserManagerHelper; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.util.Log; @@ -36,8 +35,8 @@ import com.android.systemui.classifier.FalsingLog; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.car.hvac.TemperatureView; @@ -461,16 +460,11 @@ public class CarStatusBar extends StatusBar implements } } - - public boolean hasDockedTask() { - return Recents.getSystemServices().hasDockedTask(); - } - /** - * An implementation of SysUiTaskStackChangeListener, that listens for changes in the system + * An implementation of TaskStackChangeListener, that listens for changes in the system * task stack and notifies the navigation bar. */ - private class TaskStackListenerImpl extends SysUiTaskStackChangeListener { + private class TaskStackListenerImpl extends TaskStackChangeListener { @Override public void onTaskStackChanged() { try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index 67e512cf23f9..618a4c134049 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -22,7 +22,7 @@ import static android.content.DialogInterface.BUTTON_POSITIVE; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; -import android.car.user.CarUserManagerHelper; +import android.car.userlib.CarUserManagerHelper; import android.content.Context; import android.content.DialogInterface; import android.content.pm.UserInfo; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index d5a52740c6d4..a3e982e77522 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -35,6 +35,8 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; @@ -58,7 +60,6 @@ import com.android.systemui.EventLogTags; import com.android.systemui.ForegroundServiceController; import com.android.systemui.R; import com.android.systemui.UiOffloadThread; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AmbientPulseManager; @@ -127,11 +128,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. Dependency.get(NotificationListener.class); protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class); + protected IDreamManager mDreamManager; protected IStatusBarService mBarService; protected NotificationPresenter mPresenter; protected Callback mCallback; protected PowerManager mPowerManager; - protected SystemServicesProxy mSystemServicesProxy; protected NotificationListenerService.RankingMap mLatestRankingMap; protected HeadsUpManager mHeadsUpManager; protected NotificationData mNotificationData; @@ -223,8 +224,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + mDreamManager = IDreamManager.Stub.asInterface( + ServiceManager.checkService(DreamService.DREAM_SERVICE)); mMessagingUtil = new NotificationMessagingUtil(context); - mSystemServicesProxy = SystemServicesProxy.getInstance(mContext); mGroupManager.setPendingEntries(mPendingNotifications); } @@ -687,7 +689,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } else { // Stop screensaver if the notification has a fullscreen intent. // (like an incoming phone call) - SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); + Dependency.get(UiOffloadThread.class).submit(() -> { + try { + mDreamManager.awaken(); + } catch (RemoteException e) { + e.printStackTrace(); + } + }); // not immersive & a fullscreen alert should be shown if (DEBUG) @@ -898,7 +906,13 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. return false; } - boolean inUse = mPowerManager.isScreenOn() && !mSystemServicesProxy.isDreaming(); + boolean isDreaming = false; + try { + isDreaming = mDreamManager.isDreaming(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to query dream manager.", e); + } + boolean inUse = mPowerManager.isScreenOn() && !isDreaming; if (!inUse) { if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java index 4f957bfcbbcc..c7ab27ba715d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java @@ -67,9 +67,15 @@ public class ContextualButton extends ButtonDispatcher { } protected KeyButtonDrawable getNewDrawable() { - return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */); + return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId, + false /* shadow */); } + /** + * This context is from the view that could be stale after rotation or config change. To get + * correct resources use getApplicationContext() as well. + * @return current view context + */ protected Context getContext() { return getCurrentView().getContext(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index cbbb0e3dea96..9c579daa38c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -35,6 +35,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.IdRes; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.Fragment; import android.app.IActivityManager; @@ -88,8 +89,8 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; @@ -284,7 +285,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { mNavigationBarView = (NavigationBarView) view; mNavigationBarView.setDisabledFlags(mDisabledFlags1); - mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel()); + mNavigationBarView.setComponents(mStatusBar.getPanel()); mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); mNavigationBarView.setOnTouchListener(this::onNavigationTouch); if (savedInstanceState != null) { @@ -946,7 +947,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private boolean onLongPressRecents() { if (mRecents == null || !ActivityTaskManager.supportsMultiWindow(getContext()) || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible() - || Recents.getConfiguration().isLowRamDevice + || ActivityManager.isLowRamDeviceStatic() // If we are connected to the overview service, then disable the recents button || mOverviewProxyService.getProxy() != null) { return false; @@ -1110,7 +1111,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } }; - class TaskStackListenerImpl extends SysUiTaskStackChangeListener { + class TaskStackListenerImpl extends TaskStackChangeListener { // Invalidate any rotation suggestion on task change or activity orientation change // Note: all callbacks happen on main thread 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 8c02e1f8220b..62d2099204e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -16,93 +16,36 @@ package com.android.systemui.statusbar.phone; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_TOP; - -import android.app.ActivityManager; import android.content.Context; -import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Rect; import android.view.MotionEvent; -import android.view.VelocityTracker; import android.view.View; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.RecentsComponent; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.tuner.TunerService; /** - * Class to detect gestures on the navigation bar. + * TODO: Remove and replace with QuickStepController */ -public class NavigationBarGestureHelper implements TunerService.Tunable, GestureHelper { - - private static final String TAG = "NavBarGestureHelper"; - private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture"; - /** - * When dragging from the navigation bar, we drag in recents. - */ - public static final int DRAG_MODE_NONE = -1; - - /** - * When dragging from the navigation bar, we drag in recents. - */ - public static final int DRAG_MODE_RECENTS = 0; +public class NavigationBarGestureHelper implements GestureHelper { - /** - * When dragging from the navigation bar, we drag the divider. - */ - public static final int DRAG_MODE_DIVIDER = 1; + private static final String TAG = "NavigationBarGestureHelper"; - private RecentsComponent mRecentsComponent; - private Divider mDivider; - private Context mContext; private NavigationBarView mNavigationBarView; - private boolean mIsVertical; private final QuickStepController mQuickStepController; - private final int mScrollTouchSlop; private final StatusBar mStatusBar; - private int mTouchDownX; - private int mTouchDownY; - private boolean mDownOnRecents; - private VelocityTracker mVelocityTracker; - - private boolean mDockWindowEnabled; - private boolean mDockWindowTouchSlopExceeded; - private int mDragMode; public NavigationBarGestureHelper(Context context) { - mContext = context; mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class); - Resources r = context.getResources(); - mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance); mQuickStepController = new QuickStepController(context); - Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE); } - public void destroy() { - Dependency.get(TunerService.class).removeTunable(this); - } - - public void setComponents(RecentsComponent recentsComponent, Divider divider, - NavigationBarView navigationBarView) { - mRecentsComponent = recentsComponent; - mDivider = divider; + public void setComponents(NavigationBarView navigationBarView) { mNavigationBarView = navigationBarView; mQuickStepController.setComponents(mNavigationBarView); } public void setBarState(boolean isVertical, boolean isRTL) { - mIsVertical = isVertical; mQuickStepController.setBarState(isVertical, isRTL); } @@ -110,22 +53,14 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture if (!canHandleGestures()) { return false; } - boolean result = mQuickStepController.onInterceptTouchEvent(event); - if (mDockWindowEnabled) { - result |= interceptDockWindowEvent(event); - } - return result; + return mQuickStepController.onInterceptTouchEvent(event); } public boolean onTouchEvent(MotionEvent event) { if (!canHandleGestures()) { return false; } - boolean result = mQuickStepController.onTouchEvent(event); - if (mDockWindowEnabled) { - result |= handleDockWindowEvent(event); - } - return result; + return mQuickStepController.onTouchEvent(event); } public void onDraw(Canvas canvas) { @@ -144,152 +79,7 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture mQuickStepController.onNavigationButtonLongPress(v); } - private boolean interceptDockWindowEvent(MotionEvent event) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - handleDragActionDownEvent(event); - break; - case MotionEvent.ACTION_MOVE: - return handleDragActionMoveEvent(event); - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - handleDragActionUpEvent(event); - break; - } - return false; - } - - private boolean handleDockWindowEvent(MotionEvent event) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - handleDragActionDownEvent(event); - break; - case MotionEvent.ACTION_MOVE: - handleDragActionMoveEvent(event); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - handleDragActionUpEvent(event); - break; - } - return true; - } - - private void handleDragActionDownEvent(MotionEvent event) { - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(event); - mDockWindowTouchSlopExceeded = false; - mTouchDownX = (int) event.getX(); - mTouchDownY = (int) event.getY(); - - if (mNavigationBarView != null) { - View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView(); - if (recentsButton != null) { - mDownOnRecents = mTouchDownX >= recentsButton.getLeft() - && mTouchDownX <= recentsButton.getRight() - && mTouchDownY >= recentsButton.getTop() - && mTouchDownY <= recentsButton.getBottom(); - } else { - mDownOnRecents = false; - } - } - } - - private boolean handleDragActionMoveEvent(MotionEvent event) { - mVelocityTracker.addMovement(event); - int x = (int) event.getX(); - int y = (int) event.getY(); - int xDiff = Math.abs(x - mTouchDownX); - int yDiff = Math.abs(y - mTouchDownY); - if (mDivider == null || mRecentsComponent == null) { - return false; - } - if (!mDockWindowTouchSlopExceeded) { - boolean touchSlopExceeded = !mIsVertical - ? yDiff > mScrollTouchSlop && yDiff > xDiff - : xDiff > mScrollTouchSlop && xDiff > yDiff; - if (mDownOnRecents && touchSlopExceeded - && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) { - Rect initialBounds = null; - int dragMode = calculateDragMode(); - int createMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; - if (dragMode == DRAG_MODE_DIVIDER) { - initialBounds = new Rect(); - mDivider.getView().calculateBoundsForPosition(mIsVertical - ? (int) event.getRawX() - : (int) event.getRawY(), - mDivider.getView().isHorizontalDivision() - ? DOCKED_TOP - : DOCKED_LEFT, - initialBounds); - } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX - < mContext.getResources().getDisplayMetrics().widthPixels / 2) { - createMode = SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; - } - boolean docked = mRecentsComponent.splitPrimaryTask(dragMode, createMode, - initialBounds, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE); - if (docked) { - mDragMode = dragMode; - if (mDragMode == DRAG_MODE_DIVIDER) { - mDivider.getView().startDragging(false /* animate */, true /* touching*/); - } - mDockWindowTouchSlopExceeded = true; - return true; - } - } - } else { - if (mDragMode == DRAG_MODE_DIVIDER) { - int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX(); - SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm() - .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */); - mDivider.getView().resizeStack(position, snapTarget.position, snapTarget); - } else if (mDragMode == DRAG_MODE_RECENTS) { - mRecentsComponent.onDraggingInRecents(event.getRawY()); - } - } - return false; - } - - private void handleDragActionUpEvent(MotionEvent event) { - mVelocityTracker.addMovement(event); - mVelocityTracker.computeCurrentVelocity(1000); - if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) { - if (mDragMode == DRAG_MODE_DIVIDER) { - mDivider.getView().stopDragging(mIsVertical - ? (int) event.getRawX() - : (int) event.getRawY(), - mIsVertical - ? mVelocityTracker.getXVelocity() - : mVelocityTracker.getYVelocity(), - true /* avoidDismissStart */, false /* logMetrics */); - } else if (mDragMode == DRAG_MODE_RECENTS) { - mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity()); - } - } - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - private boolean canHandleGestures() { return !mStatusBar.isKeyguardShowing(); } - - private int calculateDragMode() { - if (mIsVertical && !mDivider.getView().isHorizontalDivision()) { - return DRAG_MODE_DIVIDER; - } - if (!mIsVertical && mDivider.getView().isHorizontalDivision()) { - return DRAG_MODE_DIVIDER; - } - return DRAG_MODE_RECENTS; - } - - @Override - public void onTuningChanged(String key, String newValue) { - switch (key) { - case KEY_DOCK_WINDOW_GESTURE: - mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0); - break; - } - } } 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 71b35e043f77..e5c910069f82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -144,8 +144,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav private Configuration mConfiguration; private NavigationBarInflaterView mNavigationInflaterView; - private RecentsComponent mRecentsComponent; - private Divider mDivider; private RecentsOnboarding mRecentsOnboarding; private NotificationPanelView mPanelView; @@ -314,14 +312,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav return mBarTransitions.getLightTransitionsController(); } - public void setComponents(RecentsComponent recentsComponent, Divider divider, - NotificationPanelView panel) { - mRecentsComponent = recentsComponent; - mDivider = divider; + public void setComponents(NotificationPanelView panel) { mPanelView = panel; if (mGestureHelper instanceof NavigationBarGestureHelper) { - ((NavigationBarGestureHelper) mGestureHelper).setComponents( - recentsComponent, divider, this); + ((NavigationBarGestureHelper) mGestureHelper).setComponents(this); } } @@ -1078,7 +1072,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav @Override public void onPluginDisconnected(NavGesture plugin) { NavigationBarGestureHelper defaultHelper = new NavigationBarGestureHelper(getContext()); - defaultHelper.setComponents(mRecentsComponent, mDivider, this); + defaultHelper.setComponents(this); if (mGestureHelper != null) { mGestureHelper.destroy(); } 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 1afdc66b9227..553165b40153 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -67,8 +67,8 @@ import com.android.systemui.SysUiServiceProvider; import com.android.systemui.UiOffloadThread; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.BluetoothController; @@ -797,7 +797,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mIconController.setIconVisibility(mSlotDataSaver, isDataSaving); } - private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() { + private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() { @Override public void onTaskStackChanged() { // Listen for changes to stacks and then check which instant apps are foreground. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index ff38380b7aa8..226b6453dbab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -102,6 +102,8 @@ import android.os.UserManager; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; @@ -154,6 +156,7 @@ import com.android.systemui.Interpolators; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.RecentsComponent; +import com.android.systemui.SysUiServiceProvider; import com.android.systemui.SystemUI; import com.android.systemui.SystemUIFactory; import com.android.systemui.UiOffloadThread; @@ -179,10 +182,6 @@ import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.recents.Recents; import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; -import com.android.systemui.recents.events.activity.UndockingTaskEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.stackdivider.WindowManagerProxy; @@ -635,6 +634,8 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + mDreamManager = IDreamManager.Stub.asInterface( + ServiceManager.checkService(DreamService.DREAM_SERVICE)); mDisplay = mWindowManager.getDefaultDisplay(); updateDisplaySize(); @@ -1214,17 +1215,18 @@ public class StatusBar extends SystemUI implements DemoMode, int createMode = navbarPos == NAV_BAR_POS_LEFT ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; - return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode, - null, metricsDockAction); + return mRecents.splitPrimaryTask(createMode, null, metricsDockAction); } else { Divider divider = getComponent(Divider.class); - if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) { - // Undocking from the minimized state is not supported - return false; - } else { - EventBus.getDefault().send(new UndockingTaskEvent()); - if (metricsUndockAction != -1) { - mMetricsLogger.action(metricsUndockAction); + if (divider != null) { + if (divider.isMinimized() && !divider.isHomeStackResizable()) { + // Undocking from the minimized state is not supported + return false; + } else { + divider.onUndockingTask(); + if (metricsUndockAction != -1) { + mMetricsLogger.action(metricsUndockAction); + } } } } @@ -4246,12 +4248,12 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void appTransitionCancelled() { - EventBus.getDefault().send(new AppTransitionFinishedEvent()); + getComponent(Divider.class).onAppTransitionFinished(); } @Override public void appTransitionFinished() { - EventBus.getDefault().send(new AppTransitionFinishedEvent()); + getComponent(Divider.class).onAppTransitionFinished(); } @Override @@ -4663,6 +4665,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected WindowManager mWindowManager; protected IWindowManager mWindowManagerService; + private IDreamManager mDreamManager; protected Display mDisplay; @@ -4967,7 +4970,13 @@ public class StatusBar extends SystemUI implements DemoMode, } void awakenDreams() { - SystemServicesProxy.getInstance(mContext).awakenDreamsAsync(); + Dependency.get(UiOffloadThread.class).submit(() -> { + try { + mDreamManager.awaken(); + } catch (RemoteException e) { + e.printStackTrace(); + } + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index e9efaa14ef7c..0a72c3f9e8d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -17,10 +17,7 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.UserManager; @@ -38,14 +35,13 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final ArrayList<Callback> mCallbacks = new ArrayList<>(); - private final WifiStateReceiver mWifiStateReceiver = new WifiStateReceiver(); private final ConnectivityManager mConnectivityManager; private final WifiManager mWifiManager; private final Context mContext; private int mHotspotState; private int mNumConnectedDevices; - private boolean mWaitingForCallback; + private boolean mWaitingForTerminalState; public HotspotControllerImpl(Context context) { mContext = context; @@ -63,7 +59,9 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("HotspotController state:"); - pw.print(" mHotspotEnabled="); pw.println(stateToString(mHotspotState)); + pw.print(" mHotspotState="); pw.println(stateToString(mHotspotState)); + pw.print(" mNumConnectedDevices="); pw.println(mNumConnectedDevices); + pw.print(" mWaitingForTerminalState="); pw.println(mWaitingForTerminalState); } private static String stateToString(int hotspotState) { @@ -99,7 +97,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof if (DEBUG) Log.d(TAG, "removeCallback " + callback); synchronized (mCallbacks) { mCallbacks.remove(callback); - updateWifiStateListeners(!mCallbacks.isEmpty()); } } @@ -112,7 +109,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof * @param shouldListen whether we should start listening to various wifi statuses */ private void updateWifiStateListeners(boolean shouldListen) { - mWifiStateReceiver.setListening(shouldListen); if (shouldListen) { mWifiManager.registerSoftApCallback( this, @@ -129,21 +125,27 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof @Override public boolean isHotspotTransient() { - return mWaitingForCallback || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING); + return mWaitingForTerminalState || (mHotspotState == WifiManager.WIFI_AP_STATE_ENABLING); } @Override public void setHotspotEnabled(boolean enabled) { - if (mWaitingForCallback) { - if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for callback."); + if (mWaitingForTerminalState) { + if (DEBUG) Log.d(TAG, "Ignoring setHotspotEnabled; waiting for terminal state."); return; } if (enabled) { - OnStartTetheringCallback callback = new OnStartTetheringCallback(); - mWaitingForCallback = true; + mWaitingForTerminalState = true; if (DEBUG) Log.d(TAG, "Starting tethering"); - mConnectivityManager.startTethering( - ConnectivityManager.TETHERING_WIFI, false, callback); + mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false, + new ConnectivityManager.OnStartTetheringCallback() { + @Override + public void onTetheringFailed() { + if (DEBUG) Log.d(TAG, "onTetheringFailed"); + maybeResetSoftApState(); + fireHotspotChangedCallback(); + } + }); } else { mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); } @@ -155,99 +157,56 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof } /** - * Sends a hotspot changed callback with the new enabled status. Wraps - * {@link #fireHotspotChangedCallback(boolean, int)} and assumes that the number of devices has - * not changed. - * - * @param enabled whether the hotspot is enabled - */ - private void fireHotspotChangedCallback(boolean enabled) { - fireHotspotChangedCallback(enabled, mNumConnectedDevices); - } - - /** - * Sends a hotspot changed callback with the new enabled status & the number of devices - * connected to the hotspot. Be careful when calling over multiple threads, especially if one of - * them is the main thread (as it can be blocked). - * - * @param enabled whether the hotspot is enabled - * @param numConnectedDevices number of devices connected to the hotspot + * Sends a hotspot changed callback. + * Be careful when calling over multiple threads, especially if one of them is the main thread + * (as it can be blocked). */ - private void fireHotspotChangedCallback(boolean enabled, int numConnectedDevices) { + private void fireHotspotChangedCallback() { synchronized (mCallbacks) { for (Callback callback : mCallbacks) { - callback.onHotspotChanged(enabled, numConnectedDevices); + callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices); } } } @Override public void onStateChanged(int state, int failureReason) { - // Do nothing - we don't care about changing anything here. - } + // Update internal hotspot state for tracking before using any enabled/callback methods. + mHotspotState = state; + + maybeResetSoftApState(); + if (!isHotspotEnabled()) { + // Reset num devices if the hotspot is no longer enabled so we don't get ghost + // counters. + mNumConnectedDevices = 0; + } - @Override - public void onNumClientsChanged(int numConnectedDevices) { - mNumConnectedDevices = numConnectedDevices; - fireHotspotChangedCallback(isHotspotEnabled(), numConnectedDevices); + fireHotspotChangedCallback(); } - private final class OnStartTetheringCallback extends - ConnectivityManager.OnStartTetheringCallback { - @Override - public void onTetheringStarted() { - if (DEBUG) Log.d(TAG, "onTetheringStarted"); - mWaitingForCallback = false; - // Don't fire a callback here, instead wait for the next update from wifi. + private void maybeResetSoftApState() { + if (!mWaitingForTerminalState) { + return; // Only reset soft AP state if enabled from this controller. } - - @Override - public void onTetheringFailed() { - if (DEBUG) Log.d(TAG, "onTetheringFailed"); - mWaitingForCallback = false; - // TODO(b/110697252): stopTethering must be called to reset soft ap state after failure - mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - fireHotspotChangedCallback(isHotspotEnabled()); - // TODO: Show error. + switch (mHotspotState) { + case WifiManager.WIFI_AP_STATE_FAILED: + // TODO(b/110697252): must be called to reset soft ap state after failure + mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); + // Fall through + case WifiManager.WIFI_AP_STATE_ENABLED: + case WifiManager.WIFI_AP_STATE_DISABLED: + mWaitingForTerminalState = false; + break; + case WifiManager.WIFI_AP_STATE_ENABLING: + case WifiManager.WIFI_AP_STATE_DISABLING: + default: + break; } } - /** - * Class to listen in on wifi state and update the hotspot state - */ - private final class WifiStateReceiver extends BroadcastReceiver { - private boolean mRegistered; - - public void setListening(boolean listening) { - if (listening && !mRegistered) { - if (DEBUG) Log.d(TAG, "Registering receiver"); - final IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); - mContext.registerReceiver(this, filter); - mRegistered = true; - } else if (!listening && mRegistered) { - if (DEBUG) Log.d(TAG, "Unregistering receiver"); - mContext.unregisterReceiver(this); - mRegistered = false; - } - } - - @Override - public void onReceive(Context context, Intent intent) { - int state = intent.getIntExtra( - WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); - if (DEBUG) Log.d(TAG, "onReceive " + state); - - // Update internal hotspot state for tracking before using any enabled/callback methods. - mHotspotState = state; - - if (!isHotspotEnabled()) { - // Reset num devices if the hotspot is no longer enabled so we don't get ghost - // counters. - mNumConnectedDevices = 0; - } - - fireHotspotChangedCallback(isHotspotEnabled()); - } + @Override + public void onNumClientsChanged(int numConnectedDevices) { + mNumConnectedDevices = numConnectedDevices; + fireHotspotChangedCallback(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java index f8aa28dbb945..199c4c283452 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java @@ -40,9 +40,9 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -65,7 +65,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase { private @Mock IActivityTaskManager mIActivityTaskManager; private WorkLockActivityController mController; - private SysUiTaskStackChangeListener mTaskStackListener; + private TaskStackChangeListener mTaskStackListener; @Before public void setUp() throws Exception { @@ -75,8 +75,8 @@ public class WorkLockActivityControllerTest extends SysuiTestCase { doReturn("com.example.test").when(mContext).getPackageName(); // Construct controller. Save the TaskStackListener for injecting events. - final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor = - ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class); + final ArgumentCaptor<TaskStackChangeListener> listenerCaptor = + ArgumentCaptor.forClass(TaskStackChangeListener.class); mController = new WorkLockActivityController(mContext, mActivityManager, mIActivityTaskManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 1e3d42ba6ede..b545e61a446a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.IPowerManager; import android.os.Looper; import android.os.PowerManager; +import android.service.dreams.IDreamManager; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -39,7 +40,6 @@ import android.support.test.runner.AndroidJUnit4; import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.NotificationPresenter; @@ -91,7 +91,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationData mNotificationData; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; - @Mock private SystemServicesProxy mSystemServicesProxy; + @Mock private IDreamManager mDreamManager; private PowerManager mPowerManager; private TestableNotificationEntryManager mEntryManager; @@ -111,7 +111,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mPowerManager = new PowerManager(mContext, powerManagerService, Handler.createAsync(Looper.myLooper())); - mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager, + mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager, mContext); mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, mHeadsUpManager, mNotificationData); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 5006b0b29b0c..da93327061a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -50,6 +50,7 @@ import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; +import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; import android.support.test.filters.SmallTest; import android.support.test.metricshelper.MetricsAsserts; @@ -119,9 +120,9 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardIndicationController mKeyguardIndicationController; @Mock private NotificationStackScrollLayout mStackScroller; @Mock private HeadsUpManagerPhone mHeadsUpManager; - @Mock private SystemServicesProxy mSystemServicesProxy; @Mock private NotificationPanelView mNotificationPanelView; @Mock private IStatusBarService mBarService; + @Mock private IDreamManager mDreamManager; @Mock private ScrimController mScrimController; @Mock private ArrayList<Entry> mNotificationList; @Mock private BiometricUnlockController mBiometricUnlockController; @@ -194,8 +195,7 @@ public class StatusBarTest extends SysuiTestCase { return null; }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any()); - mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager, - mContext); + mEntryManager = new TestableNotificationEntryManager(mDreamManager, mPowerManager, mContext); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache, mKeyguardIndicationController, mStackScroller, mHeadsUpManager, @@ -358,12 +358,12 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testShouldHeadsUp_nonSuppressedGroupSummary() { + public void testShouldHeadsUp_nonSuppressedGroupSummary() throws Exception { when(mPowerManager.isScreenOn()).thenReturn(true); when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false); when(mNotificationData.shouldFilterOut(any())).thenReturn(false); - when(mSystemServicesProxy.isDreaming()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH); Notification n = new Notification.Builder(getContext(), "a") @@ -379,12 +379,12 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testShouldHeadsUp_suppressedGroupSummary() { + public void testShouldHeadsUp_suppressedGroupSummary() throws Exception { when(mPowerManager.isScreenOn()).thenReturn(true); when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false); when(mNotificationData.shouldFilterOut(any())).thenReturn(false); - when(mSystemServicesProxy.isDreaming()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH); Notification n = new Notification.Builder(getContext(), "a") @@ -400,11 +400,11 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testShouldHeadsUp_suppressedHeadsUp() { + public void testShouldHeadsUp_suppressedHeadsUp() throws Exception { when(mPowerManager.isScreenOn()).thenReturn(true); when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationData.shouldFilterOut(any())).thenReturn(false); - when(mSystemServicesProxy.isDreaming()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH); when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true); @@ -418,11 +418,11 @@ public class StatusBarTest extends SysuiTestCase { } @Test - public void testShouldHeadsUp_noSuppressedHeadsUp() { + public void testShouldHeadsUp_noSuppressedHeadsUp() throws Exception { when(mPowerManager.isScreenOn()).thenReturn(true); when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationData.shouldFilterOut(any())).thenReturn(false); - when(mSystemServicesProxy.isDreaming()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH); when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false); @@ -690,10 +690,10 @@ public class StatusBarTest extends SysuiTestCase { public static class TestableNotificationEntryManager extends NotificationEntryManager { - public TestableNotificationEntryManager(SystemServicesProxy systemServicesProxy, + public TestableNotificationEntryManager(IDreamManager dreamManager, PowerManager powerManager, Context context) { super(context); - mSystemServicesProxy = systemServicesProxy; + mDreamManager = dreamManager; mPowerManager = powerManager; } diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java new file mode 100644 index 000000000000..5bec1a94e915 --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/Chunk.java @@ -0,0 +1,54 @@ +package com.android.server.backup.encryption.chunk; + +import android.util.proto.ProtoInputStream; + +import java.io.IOException; + +/** + * Information about a chunk entry in a protobuf. Only used for reading from a {@link + * ProtoInputStream}. + */ +public class Chunk { + /** + * Reads a Chunk from a {@link ProtoInputStream}. Expects the message to be of format {@link + * ChunksMetadataProto.Chunk}. + * + * @param inputStream currently at a {@link ChunksMetadataProto.Chunk} message. + * @throws IOException when the message is not structured as expected or a field can not be + * read. + */ + static Chunk readFromProto(ProtoInputStream inputStream) throws IOException { + Chunk result = new Chunk(); + + while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (inputStream.getFieldNumber()) { + case (int) ChunksMetadataProto.Chunk.HASH: + result.mHash = inputStream.readBytes(ChunksMetadataProto.Chunk.HASH); + break; + case (int) ChunksMetadataProto.Chunk.LENGTH: + result.mLength = inputStream.readInt(ChunksMetadataProto.Chunk.LENGTH); + break; + } + } + + return result; + } + + private int mLength; + private byte[] mHash; + + /** Private constructor. This class should only be instantiated by calling readFromProto. */ + private Chunk() { + // Set default values for fields in case they are not available in the proto. + mHash = new byte[]{}; + mLength = 0; + } + + public int getLength() { + return mLength; + } + + public byte[] getHash() { + return mHash; + } +}
\ No newline at end of file diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java new file mode 100644 index 000000000000..2d2e88afccf1 --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import android.annotation.Nullable; +import android.util.proto.ProtoInputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Chunk listing in a format optimized for quick look-up of chunks via their hash keys. This is + * useful when building an incremental backup. After a chunk has been produced, the algorithm can + * quickly look up whether the chunk existed in the previous backup by checking this chunk listing. + * It can then tell the server to use that chunk, through telling it the position and length of the + * chunk in the previous backup's blob. + */ +public class ChunkListing { + /** + * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format + * {@link ChunksMetadataProto.ChunkListing}. + * + * @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message. + * @throws IOException when the message is not structured as expected or a field can not be + * read. + */ + public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException { + Map<ChunkHash, Entry> entries = new HashMap(); + + long start = 0; + + while (inputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (inputStream.getFieldNumber() == (int) ChunksMetadataProto.ChunkListing.CHUNKS) { + long chunkToken = inputStream.start(ChunksMetadataProto.ChunkListing.CHUNKS); + Chunk chunk = Chunk.readFromProto(inputStream); + entries.put(new ChunkHash(chunk.getHash()), new Entry(start, chunk.getLength())); + start += chunk.getLength(); + inputStream.end(chunkToken); + } + } + + return new ChunkListing(entries); + } + + private final Map<ChunkHash, Entry> mChunksByHash; + + private ChunkListing(Map<ChunkHash, Entry> chunksByHash) { + mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash)); + } + + /** Returns {@code true} if there is a chunk with the given SHA-256 MAC key in the listing. */ + public boolean hasChunk(ChunkHash hash) { + return mChunksByHash.containsKey(hash); + } + + /** + * Returns the entry for the chunk with the given hash. + * + * @param hash The SHA-256 MAC of the plaintext of the chunk. + * @return The entry, containing position and length of the chunk in the backup blob, or null if + * it does not exist. + */ + @Nullable + public Entry getChunkEntry(ChunkHash hash) { + return mChunksByHash.get(hash); + } + + /** Returns the number of chunks in this listing. */ + public int getChunkCount() { + return mChunksByHash.size(); + } + + /** Information about a chunk entry in a backup blob - i.e., its position and length. */ + public static final class Entry { + private final int mLength; + private final long mStart; + + private Entry(long start, int length) { + mStart = start; + mLength = length; + } + + /** Returns the length of the chunk in bytes. */ + public int getLength() { + return mLength; + } + + /** Returns the start position of the chunk in the backup blob, in bytes. */ + public long getStart() { + return mStart; + } + } +} diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java new file mode 100644 index 000000000000..3a6d1f62faaa --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/EncryptedChunkOrdering.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import java.util.Arrays; + +/** + * Holds the bytes of an encrypted {@link ChunksMetadataProto.ChunkOrdering}. + * + * <p>TODO(b/116575321): After all code is ported, remove the factory method and rename + * encryptedChunkOrdering() to getBytes(). + */ +public class EncryptedChunkOrdering { + /** + * Constructs a new object holding the given bytes of an encrypted {@link + * ChunksMetadataProto.ChunkOrdering}. + * + * <p>Note that this just holds an ordering which is already encrypted, it does not encrypt the + * ordering. + */ + public static EncryptedChunkOrdering create(byte[] encryptedChunkOrdering) { + return new EncryptedChunkOrdering(encryptedChunkOrdering); + } + + private final byte[] mEncryptedChunkOrdering; + + public byte[] encryptedChunkOrdering() { + return mEncryptedChunkOrdering; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof EncryptedChunkOrdering)) { + return false; + } + + EncryptedChunkOrdering encryptedChunkOrdering = (EncryptedChunkOrdering) o; + return Arrays.equals( + mEncryptedChunkOrdering, encryptedChunkOrdering.mEncryptedChunkOrdering); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mEncryptedChunkOrdering); + } + + private EncryptedChunkOrdering(byte[] encryptedChunkOrdering) { + mEncryptedChunkOrdering = encryptedChunkOrdering; + } +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 510d333355a3..461d39d0a29a 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -629,7 +629,7 @@ public final class ActiveServices { return false; } - IIntentSender target = mAm.getIntentSenderLocked( + IIntentSender target = mAm.mPendingIntentController.getIntentSender( ActivityManager.INTENT_SENDER_SERVICE, callingPackage, callingUid, userId, null, null, 0, new Intent[]{service}, new String[]{service.resolveType(mAm.mContext.getContentResolver())}, diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 01421c7e65c2..fab967c01086 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -890,6 +890,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mRemoved = true; releaseSelfIfNeeded(); + + mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId); } private void releaseSelfIfNeeded() { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e3ea9fad599..692f9cfaa833 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -134,7 +134,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -417,7 +416,6 @@ public class ActivityManagerService extends IActivityManager.Stub private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS; - private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION; // Mock "pretend we're idle now" broadcast action to the job scheduler; declared // here so that while the job scheduler can depend on AMS, the other way around @@ -563,6 +561,7 @@ public class ActivityManagerService extends IActivityManager.Stub String mDeviceOwnerName; final UserController mUserController; + final PendingIntentController mPendingIntentController; final AppErrors mAppErrors; @@ -821,12 +820,6 @@ public class ActivityManagerService extends IActivityManager.Stub final SparseArray<UidRecord> mValidateUids = new SparseArray<>(); /** - * Set of IntentSenderRecord objects that are currently active. - */ - final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords - = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>(); - - /** * Fingerprints (hashCode()) of stack traces that we've * already logged DropBox entries for. Guarded by itself. If * something (rogue user app) forces this over @@ -1426,7 +1419,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int UPDATE_TIME_ZONE = 13; static final int PROC_START_TIMEOUT_MSG = 20; static final int KILL_APPLICATION_MSG = 22; - static final int FINALIZE_PENDING_INTENT_MSG = 23; static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26; static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27; static final int CLEAR_DNS_CACHE_MSG = 28; @@ -1445,7 +1437,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int IDLE_UIDS_MSG = 58; static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63; static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; - static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67; static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; @@ -1644,21 +1635,6 @@ public class ActivityManagerService extends IActivityManager.Stub mServices.serviceForegroundCrash( (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY)); } break; - case DISPATCH_PENDING_INTENT_CANCEL_MSG: { - RemoteCallbackList<IResultReceiver> callbacks - = (RemoteCallbackList<IResultReceiver>)msg.obj; - int N = callbacks.beginBroadcast(); - for (int i = 0; i < N; i++) { - try { - callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); - } catch (RemoteException e) { - } - } - callbacks.finishBroadcast(); - // We have to clean up the RemoteCallbackList here, because otherwise it will - // needlessly hold the enclosed callbacks until the remote process dies. - callbacks.kill(); - } break; case UPDATE_TIME_ZONE: { synchronized (ActivityManagerService.this) { for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { @@ -1738,9 +1714,6 @@ public class ActivityManagerService extends IActivityManager.Stub false, userId, reason); } } break; - case FINALIZE_PENDING_INTENT_MSG: { - ((PendingIntentRecord)msg.obj).completeFinalize(); - } break; case CHECK_EXCESSIVE_POWER_USE_MSG: { synchronized (ActivityManagerService.this) { checkExcessivePowerUsageLocked(); @@ -2354,6 +2327,7 @@ public class ActivityManagerService extends IActivityManager.Stub mSystemThread = null; mUiHandler = injector.getUiHandler(null); mUserController = null; + mPendingIntentController = null; mProcStartHandlerThread = null; mProcStartHandler = null; mHiddenApiBlacklist = null; @@ -2407,7 +2381,8 @@ public class ActivityManagerService extends IActivityManager.Stub final File systemDir = SystemServiceManager.ensureSystemDir(); // TODO: Move creation of battery stats service outside of activity manager service. - mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler); + mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, + BackgroundThread.get().getHandler()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.scheduleWriteToDisk(); mOnBattery = DEBUG_POWER ? true @@ -2438,6 +2413,9 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mStackSupervisor = mActivityTaskManager.mStackSupervisor; + mPendingIntentController = new PendingIntentController( + mHandlerThread.getLooper(), mUserController); + mProcessCpuThread = new Thread("CpuTracker") { @Override public void run() { @@ -2508,6 +2486,7 @@ public class ActivityManagerService extends IActivityManager.Stub LocalServices.addService(ActivityManagerInternal.class, new LocalService()); mActivityTaskManager.onActivityManagerInternalAdded(); mUgmInternal.onActivityManagerInternalAdded(); + mPendingIntentController.onActivityManagerInternalAdded(); // Wait for the synchronized block started in mProcessCpuThread, // so that any other access to mProcessCpuTracker from main thread // will be blocked during mProcessCpuTracker initialization. @@ -5511,55 +5490,8 @@ public class ActivityManagerService extends IActivityManager.Stub } if (packageName == null || uninstalling) { - // Remove pending intents. For now we only do this when force - // stopping users, because we have some problems when doing this - // for packages -- app widgets are not currently cleaned up for - // such packages, so they can be left with bad pending intents. - if (mIntentSenderRecords.size() > 0) { - Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> wpir = it.next(); - if (wpir == null) { - it.remove(); - continue; - } - PendingIntentRecord pir = wpir.get(); - if (pir == null) { - it.remove(); - continue; - } - if (packageName == null) { - // Stopping user, remove all objects for the user. - if (pir.key.userId != userId) { - // Not the same user, skip it. - continue; - } - } else { - if (UserHandle.getAppId(pir.uid) != appId) { - // Different app id, skip it. - continue; - } - if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { - // Different user, skip it. - continue; - } - if (!pir.key.packageName.equals(packageName)) { - // Different package, skip it. - continue; - } - } - if (!doit) { - return true; - } - didSomething = true; - it.remove(); - makeIntentSenderCanceledLocked(pir); - if (pir.key.activity != null && pir.key.activity.pendingResults != null) { - pir.key.activity.pendingResults.remove(pir.ref); - } - } - } + didSomething |= mPendingIntentController.removePendingIntentsForPackage( + packageName, userId, appId, doit); } if (doit) { @@ -6342,90 +6274,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } - return getIntentSenderLocked(type, packageName, callingUid, userId, - token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); - + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + return mAtmInternal.getIntentSender(type, packageName, callingUid, userId, + token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); + } + return mPendingIntentController.getIntentSender(type, packageName, callingUid, + userId, token, resultWho, requestCode, intents, resolvedTypes, flags, + bOptions); } catch (RemoteException e) { throw new SecurityException(e); } } } - IIntentSender getIntentSenderLocked(int type, String packageName, - int callingUid, int userId, IBinder token, String resultWho, - int requestCode, Intent[] intents, String[] resolvedTypes, int flags, - Bundle bOptions) { - if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid); - ActivityRecord activity = null; - if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - activity = ActivityRecord.isInStackLocked(token); - if (activity == null) { - Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); - return null; - } - if (activity.finishing) { - Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); - return null; - } - } - - // We're going to be splicing together extras before sending, so we're - // okay poking into any contained extras. - if (intents != null) { - for (int i = 0; i < intents.length; i++) { - intents[i].setDefusable(true); - } - } - Bundle.setDefusable(bOptions, true); - - final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; - final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; - final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; - flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT - |PendingIntent.FLAG_UPDATE_CURRENT); - - PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, - resultWho, requestCode, intents, resolvedTypes, flags, - SafeActivityOptions.fromBundle(bOptions), userId); - WeakReference<PendingIntentRecord> ref; - ref = mIntentSenderRecords.get(key); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec != null) { - if (!cancelCurrent) { - if (updateCurrent) { - if (rec.key.requestIntent != null) { - rec.key.requestIntent.replaceExtras(intents != null ? - intents[intents.length - 1] : null); - } - if (intents != null) { - intents[intents.length-1] = rec.key.requestIntent; - rec.key.allIntents = intents; - rec.key.allResolvedTypes = resolvedTypes; - } else { - rec.key.allIntents = null; - rec.key.allResolvedTypes = null; - } - } - return rec; - } - makeIntentSenderCanceledLocked(rec); - mIntentSenderRecords.remove(key); - } - if (noCreate) { - return rec; - } - rec = new PendingIntentRecord(this, key, callingUid); - mIntentSenderRecords.put(key, rec.ref); - if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - if (activity.pendingResults == null) { - activity.pendingResults - = new HashSet<WeakReference<PendingIntentRecord>>(); - } - activity.pendingResults.add(rec.ref); - } - return rec; - } - @Override public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code, Intent intent, String resolvedType, @@ -6465,44 +6326,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void cancelIntentSender(IIntentSender sender) { - if (!(sender instanceof PendingIntentRecord)) { - return; - } - synchronized(this) { - PendingIntentRecord rec = (PendingIntentRecord)sender; - try { - final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, - MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); - if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { - String msg = "Permission Denial: cancelIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " is not allowed to cancel package " - + rec.key.packageName; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - } catch (RemoteException e) { - throw new SecurityException(e); - } - cancelIntentSenderLocked(rec, true); - } - } - - void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) { - makeIntentSenderCanceledLocked(rec); - mIntentSenderRecords.remove(rec.key); - if (cleanActivity && rec.key.activity != null) { - rec.key.activity.pendingResults.remove(rec.ref); - } - } - - void makeIntentSenderCanceledLocked(PendingIntentRecord rec) { - rec.canceled = true; - RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); - if (callbacks != null) { - mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget(); - } + mPendingIntentController.cancelIntentSender(sender); } @Override @@ -10866,7 +10690,7 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println("-------------------------------------------------------------------------------"); } - dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -11159,7 +10983,7 @@ public class ActivityManagerService extends IActivityManager.Stub opti++; } synchronized (this) { - dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage); + mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage); } } else if ("processes".equals(cmd) || "p".equals(cmd)) { if (opti < args.length) { @@ -12857,61 +12681,6 @@ public class ActivityManagerService extends IActivityManager.Stub mUgmInternal.dump(pw, dumpAll, dumpPackage); } - void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll, String dumpPackage) { - boolean printed = false; - - pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); - - if (mIntentSenderRecords.size() > 0) { - // Organize these by package name, so they are easier to read. - final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); - final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); - final Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> ref = it.next(); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec == null) { - weakRefs.add(ref); - continue; - } - if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { - continue; - } - ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); - if (list == null) { - list = new ArrayList<>(); - byPackage.put(rec.key.packageName, list); - } - list.add(rec); - } - for (int i = 0; i < byPackage.size(); i++) { - ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); - printed = true; - pw.print(" * "); pw.print(byPackage.keyAt(i)); - pw.print(": "); pw.print(intents.size()); pw.println(" items"); - for (int j = 0; j < intents.size(); j++) { - pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); - if (dumpAll) { - intents.get(j).dump(pw, " "); - } - } - } - if (weakRefs.size() > 0) { - printed = true; - pw.println(" * WEAK REFS:"); - for (int i = 0; i < weakRefs.size(); i++) { - pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); - } - } - } - - if (!printed) { - pw.println(" (nothing)"); - } - } - private static final int dumpProcessList(PrintWriter pw, ActivityManagerService service, List list, String prefix, String normalLabel, String persistentLabel, @@ -15186,24 +14955,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, - boolean fgRequired, String callingPackage, int userId) - throws TransactionTooLargeException { - synchronized(this) { - if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, - "startServiceInPackage: " + service + " type=" + resolvedType); - final long origId = Binder.clearCallingIdentity(); - ComponentName res; - try { - res = mServices.startServiceLocked(null, service, - resolvedType, -1, uid, fgRequired, callingPackage, userId); - } finally { - Binder.restoreCallingIdentity(origId); - } - return res; - } - } - @Override public int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) { @@ -21092,6 +20843,46 @@ public class ActivityManagerService extends IActivityManager.Stub public void finishBooting() { ActivityManagerService.this.finishBooting(); } + + @Override + public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, + long duration, String tag) { + synchronized (ActivityManagerService.this) { + ActivityManagerService.this.tempWhitelistForPendingIntentLocked( + callerPid, callerUid, targetUid, duration, tag); + } + } + + @Override + public int broadcastIntentInPackage(String packageName, int uid, Intent intent, + String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, + Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, + boolean sticky, int userId) { + synchronized (ActivityManagerService.this) { + return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid, + intent, resolvedType, resultTo, resultCode, resultData, resultExtras, + requiredPermission, bOptions, serialized, sticky, userId); + } + } + + @Override + public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, + boolean fgRequired, String callingPackage, int userId) + throws TransactionTooLargeException { + synchronized(ActivityManagerService.this) { + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, + "startServiceInPackage: " + service + " type=" + resolvedType); + final long origId = Binder.clearCallingIdentity(); + ComponentName res; + try { + res = mServices.startServiceLocked(null, service, + resolvedType, -1, uid, fgRequired, callingPackage, userId); + } finally { + Binder.restoreCallingIdentity(origId); + } + return res; + } + } } /** diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 35a1eb8ff616..9f59bd8db62a 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2450,13 +2450,24 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (shouldSleepOrShutDownActivities() && mLastPausedActivity == next && mStackSupervisor.allPausedActivitiesComplete()) { - // Make sure we have executed any pending transitions, since there - // should be nothing left to do at this point. - executeAppTransition(options); - if (DEBUG_STATES) Slog.d(TAG_STATES, - "resumeTopActivityLocked: Going to sleep and all paused"); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - return false; + // If the current top activity may be able to occlude keyguard but the occluded state + // has not been set, update visibility and check again if we should continue to resume. + boolean nothingToResume = true; + if (!mService.mShuttingDown && !mTopActivityOccludesKeyguard + && next.canShowWhenLocked()) { + ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, + !PRESERVE_WINDOWS); + nothingToResume = shouldSleepActivities(); + } + if (nothingToResume) { + // Make sure we have executed any pending transitions, since there + // should be nothing left to do at this point. + executeAppTransition(options); + if (DEBUG_STATES) Slog.d(TAG_STATES, + "resumeTopActivityLocked: Going to sleep and all paused"); + if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); + return false; + } } // Make sure that the user who owns this activity is started. If not, @@ -4144,7 +4155,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai for (WeakReference<PendingIntentRecord> apr : r.pendingResults) { PendingIntentRecord rec = apr.get(); if (rec != null) { - mService.mAm.cancelIntentSenderLocked(rec, false); + mService.mPendingIntentController.cancelIntentSender(rec, false); } } r.pendingResults = null; diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 177e2f563a4b..1fb8f871efcd 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -126,7 +126,7 @@ class ActivityStartInterceptor { private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) { Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary(); - final IIntentSender target = mService.mAm.getIntentSenderLocked( + final IIntentSender target = mService.getIntentSenderLocked( INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/, null /*resultCode*/, 0 /*requestCode*/, new Intent[] { mIntent }, new String[] { mResolvedType }, diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 7da0519ef2f0..890aafefdf0f 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -783,7 +783,7 @@ class ActivityStarter { if (aInfo != null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, userId)) { - IIntentSender target = mService.mAm.getIntentSenderLocked( + IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingUid, userId, null, null, 0, new Intent[]{intent}, new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT @@ -1096,7 +1096,7 @@ class ActivityStarter { } } - IIntentSender target = mService.mAm.getIntentSenderLocked( + IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, "android", appCallingUid, userId, null, null, 0, new Intent[] { intent }, new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 4dc28510c5ec..add9f2a7e9d8 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -239,7 +239,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -276,6 +278,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { UriGrantsManagerInternal mUgmInternal; private PackageManagerInternal mPmInternal; private ActivityTaskManagerInternal mInternal; + PendingIntentController mPendingIntentController; /* Global service lock used by the package the owns this service. */ Object mGlobalLock; ActivityStackSupervisor mStackSupervisor; @@ -628,6 +631,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final File systemDir = SystemServiceManager.ensureSystemDir(); mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir); mCompatModePackages = new CompatModePackages(this, systemDir, mH); + mPendingIntentController = mAm.mPendingIntentController; mTempConfig.setToDefaults(); mTempConfig.setLocales(LocaleList.getDefault()); @@ -5019,6 +5023,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } + IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId, + IBinder token, String resultWho, int requestCode, Intent[] intents, + String[] resolvedTypes, int flags, Bundle bOptions) { + + ActivityRecord activity = null; + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + activity = ActivityRecord.isInStackLocked(token); + if (activity == null) { + Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); + return null; + } + if (activity.finishing) { + Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); + return null; + } + } + + final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName, + callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags, + bOptions); + final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; + if (noCreate) { + return rec; + } + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + if (activity.pendingResults == null) { + activity.pendingResults = new HashSet<>(); + } + activity.pendingResults.add(rec.ref); + } + return rec; + } + // TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities private void startTimeTrackingFocusedActivityLocked() { final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity(); @@ -5310,6 +5347,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, + String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { + synchronized (mGlobalLock) { + return getActivityStartController().startActivitiesInPackage(uid, callingPackage, + intents, resolvedTypes, resultTo, options, userId, validateIncomingUser, + originatingPendingIntent); + } + } + + @Override + public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, + String callingPackage, Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, SafeActivityOptions options, + int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, + PendingIntentRecord originatingPendingIntent) { + synchronized (mGlobalLock) { + return getActivityStartController().startActivityInPackage(uid, realCallingPid, + realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho, + requestCode, startFlags, options, userId, inTask, reason, + validateIncomingUser, originatingPendingIntent); + } + } + + @Override public int startActivityAsUser(IApplicationThread caller, String callerPacakge, Intent intent, Bundle options, int userId) { return ActivityTaskManagerService.this.startActivityAsUser( @@ -5684,5 +5746,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } }); } + + @Override + public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho, + int requestCode, int resultCode, Intent data) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); + if (r != null && r.getStack() != null) { + r.getStack().sendActivityResultLocked(callingUid, r, resultWho, requestCode, + resultCode, data); + } + } + } + + @Override + public void clearPendingResultForActivity(IBinder activityToken, + WeakReference<PendingIntentRecord> pir) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); + if (r != null && r.pendingResults != null) { + r.pendingResults.remove(pir); + } + } + } + + @Override + public IIntentSender getIntentSender(int type, String packageName, + int callingUid, int userId, IBinder token, String resultWho, + int requestCode, Intent[] intents, String[] resolvedTypes, int flags, + Bundle bOptions) { + synchronized (mGlobalLock) { + return getIntentSenderLocked(type, packageName, callingUid, userId, token, + resultWho, requestCode, intents, resolvedTypes, flags, bOptions); + } + } } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 16c3235cd729..e2035f67031a 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -741,7 +741,7 @@ public final class BroadcastQueue { // Show a permission review UI only for explicit broadcast from a foreground app if (callerForeground && receiverRecord.intent.getComponent() != null) { - IIntentSender target = mService.getIntentSenderLocked( + IIntentSender target = mService.mPendingIntentController.getIntentSender( ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage, receiverRecord.callingUid, receiverRecord.userId, null, null, 0, new Intent[]{receiverRecord.intent}, diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index ee4e36ff1fd1..cfe282917f3b 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -29,16 +29,20 @@ import static android.view.WindowManager.TRANSIT_UNSET; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; + import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED; +import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES; import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING; +import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID; +import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED; import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; import android.util.Slog; +import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.policy.IKeyguardDismissCallback; @@ -58,19 +62,18 @@ class KeyguardController { private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM; - private final ActivityTaskManagerService mService; private final ActivityStackSupervisor mStackSupervisor; private WindowManagerService mWindowManager; private boolean mKeyguardShowing; private boolean mAodShowing; private boolean mKeyguardGoingAway; - private boolean mOccluded; private boolean mDismissalRequested; - private ActivityRecord mDismissingKeyguardActivity; private int mBeforeUnoccludeTransit; private int mVisibilityTransactionDepth; - private SleepToken mSleepToken; + // TODO(b/111955725): Support multiple external displays private int mSecondaryDisplayShowing = INVALID_DISPLAY; + private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); + private final ActivityTaskManagerService mService; KeyguardController(ActivityTaskManagerService service, ActivityStackSupervisor stackSupervisor) { @@ -87,8 +90,8 @@ class KeyguardController { * on the given display, false otherwise */ boolean isKeyguardOrAodShowing(int displayId) { - return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway && - (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); + return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway + && !isDisplayOccluded(displayId); } /** @@ -96,8 +99,7 @@ class KeyguardController { * display, false otherwise */ boolean isKeyguardShowing(int displayId) { - return mKeyguardShowing && !mKeyguardGoingAway && - (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing); + return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId); } /** @@ -133,6 +135,7 @@ class KeyguardController { if (showingChanged) { dismissDockedStackIfNeeded(); setKeyguardGoingAway(false); + // TODO(b/113840485): Check usage for non-default display mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay( isKeyguardOrAodShowing(DEFAULT_DISPLAY)); if (keyguardShowing) { @@ -248,7 +251,8 @@ class KeyguardController { // already the dismissing activity, in which case we don't allow it to repeatedly dismiss // Keyguard. return dismissKeyguard && canDismissKeyguard() && !mAodShowing - && (mDismissalRequested || r != mDismissingKeyguardActivity); + && (mDismissalRequested + || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r); } /** @@ -259,44 +263,16 @@ class KeyguardController { } private void visibilitiesUpdated() { - final boolean lastOccluded = mOccluded; - final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; - mOccluded = false; - mDismissingKeyguardActivity = null; - + boolean requestDismissKeyguard = false; for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - - // Only the top activity of the focused stack on the default display may control - // occluded state. - if (display.mDisplayId == DEFAULT_DISPLAY - && mStackSupervisor.isTopDisplayFocusedStack(stack)) { - - // A dismissing activity occludes Keyguard in the insecure case for legacy - // reasons. - final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity(); - mOccluded = - stack.topActivityOccludesKeyguard() - || (topDismissing != null - && stack.topRunningActivityLocked() == topDismissing - && canShowWhileOccluded( - true /* dismissKeyguard */, - false /* showWhenLocked */)); - } - - if (mDismissingKeyguardActivity == null - && stack.getTopDismissingKeyguardActivity() != null) { - mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity(); - } - } - } - mOccluded |= mWindowManager.isShowingDream(); - if (mOccluded != lastOccluded) { - handleOccludedChanged(); + final KeyguardDisplayState state = getDisplay(display.mDisplayId); + state.visibilitiesUpdated(this, display); + requestDismissKeyguard |= state.mRequestDismissKeyguard; } - if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) { + + // Dismissing Keyguard happens globally using the information from all displays. + if (requestDismissKeyguard) { handleDismissKeyguard(); } } @@ -305,7 +281,7 @@ class KeyguardController { * Called when occluded state changed. */ private void handleOccludedChanged() { - mWindowManager.onKeyguardOccludedChanged(mOccluded); + mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY)); if (isKeyguardLocked()) { mWindowManager.deferSurfaceLayout(); try { @@ -322,14 +298,13 @@ class KeyguardController { } /** - * Called when somebody might want to dismiss the Keyguard. + * Called when somebody wants to dismiss the Keyguard via the flag. */ private void handleDismissKeyguard() { // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded. - if (!mOccluded && mDismissingKeyguardActivity != null - && mWindowManager.isKeyguardSecure()) { + if (mWindowManager.isKeyguardSecure()) { mWindowManager.dismissKeyguard(null /* callback */, null /* message */); mDismissalRequested = true; @@ -345,6 +320,10 @@ class KeyguardController { } } + private boolean isDisplayOccluded(int displayId) { + return getDisplay(displayId).mOccluded; + } + /** * @return true if Keyguard can be currently dismissed without entering credentials. */ @@ -355,12 +334,14 @@ class KeyguardController { private int resolveOccludeTransit() { if (mBeforeUnoccludeTransit != TRANSIT_UNSET && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE - && mOccluded) { + // TODO(b/113840485): Handle app transition for individual display. + && isDisplayOccluded(DEFAULT_DISPLAY)) { // Reuse old transit in case we are occluding Keyguard again, meaning that we never // actually occclude/unocclude Keyguard, but just run a normal transition. return mBeforeUnoccludeTransit; - } else if (!mOccluded) { + // TODO(b/113840485): Handle app transition for individual display. + } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) { // Save transit in case we dismiss/occlude Keyguard shortly after. mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition(); @@ -371,7 +352,8 @@ class KeyguardController { } private void dismissDockedStackIfNeeded() { - if (mKeyguardShowing && mOccluded) { + // TODO(b/113840485): Handle docked stack for individual display. + if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) { // The lock screen is currently showing, but is occluded by a window that can // show on top of the lock screen. In this can we want to dismiss the docked // stack since it will be complicated/risky to try to put the activity on top @@ -386,11 +368,116 @@ class KeyguardController { } private void updateKeyguardSleepToken() { - if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { - mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY); - } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) { - mSleepToken.release(); - mSleepToken = null; + for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) { + final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx); + final KeyguardDisplayState state = getDisplay(display.mDisplayId); + if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) { + state.acquiredSleepToken(); + } else if (!isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken != null) { + state.releaseSleepToken(); + } + } + } + + private KeyguardDisplayState getDisplay(int displayId) { + if (mDisplayStates.get(displayId) == null) { + mDisplayStates.append(displayId, + new KeyguardDisplayState(mService, displayId)); + } + return mDisplayStates.get(displayId); + } + + void onDisplayRemoved(int displayId) { + if (mDisplayStates.get(displayId) != null) { + mDisplayStates.get(displayId).onRemoved(); + mDisplayStates.remove(displayId); + } + } + + /** Represents Keyguard state per individual display. */ + private static class KeyguardDisplayState { + private final int mDisplayId; + private boolean mOccluded; + private ActivityRecord mDismissingKeyguardActivity; + private boolean mRequestDismissKeyguard; + private final ActivityTaskManagerService mService; + private SleepToken mSleepToken; + + KeyguardDisplayState(ActivityTaskManagerService service, int displayId) { + mService = service; + mDisplayId = displayId; + } + + void onRemoved() { + mDismissingKeyguardActivity = null; + releaseSleepToken(); + } + + void acquiredSleepToken() { + if (mSleepToken == null) { + mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId); + } + } + + void releaseSleepToken() { + if (mSleepToken != null) { + mSleepToken.release(); + mSleepToken = null; + } + } + + void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) { + final boolean lastOccluded = mOccluded; + final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity; + mRequestDismissKeyguard = false; + mOccluded = false; + mDismissingKeyguardActivity = null; + + // Only the top activity of the focused stack on each display may control it's + // occluded state. + final ActivityStack focusedStack = display.getFocusedStack(); + if (focusedStack != null) { + final ActivityRecord topDismissing = + focusedStack.getTopDismissingKeyguardActivity(); + mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null + && focusedStack.topRunningActivityLocked() == topDismissing + && controller.canShowWhileOccluded( + true /* dismissKeyguard */, + false /* showWhenLocked */)); + if (focusedStack.getTopDismissingKeyguardActivity() != null) { + mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity(); + } + mOccluded |= controller.mWindowManager.isShowingDream(); + } + + // TODO(b/113840485): Handle app transition for individual display. + // For now, only default display can change occluded. + if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) { + controller.handleOccludedChanged(); + } + if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded + && mDismissingKeyguardActivity != null + && controller.mWindowManager.isKeyguardSecure()) { + mRequestDismissKeyguard = true; + } + } + + void dumpStatus(PrintWriter pw, String prefix) { + final StringBuilder sb = new StringBuilder(); + sb.append(prefix); + sb.append(" Occluded=").append(mOccluded) + .append(" DismissingKeyguardActivity=") + .append(mDismissingKeyguardActivity) + .append(" at display=") + .append(mDisplayId); + pw.println(sb.toString()); + } + + void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(DISPLAY_ID, mDisplayId); + proto.write(KEYGUARD_OCCLUDED, mOccluded); + proto.end(token); } } @@ -399,8 +486,7 @@ class KeyguardController { pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing); pw.println(prefix + " mAodShowing=" + mAodShowing); pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway); - pw.println(prefix + " mOccluded=" + mOccluded); - pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity); + dumpDisplayStates(pw, prefix); pw.println(prefix + " mDismissalRequested=" + mDismissalRequested); pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); } @@ -408,7 +494,19 @@ class KeyguardController { void writeToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(KEYGUARD_SHOWING, mKeyguardShowing); - proto.write(KEYGUARD_OCCLUDED, mOccluded); + writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES); proto.end(token); } + + private void dumpDisplayStates(PrintWriter pw, String prefix) { + for (int i = 0; i < mDisplayStates.size(); i++) { + mDisplayStates.valueAt(i).dumpStatus(pw, prefix); + } + } + + private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) { + for (int i = 0; i < mDisplayStates.size(); i++) { + mDisplayStates.valueAt(i).writeToProto(proto, fieldId); + } + } } diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java new file mode 100644 index 000000000000..a9c00a70650c --- /dev/null +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.app.Activity; +import android.app.ActivityManagerInternal; +import android.app.AppGlobals; +import android.app.PendingIntent; +import android.content.IIntentSender; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Slog; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for {@link ActivityManagerService} responsible for managing pending intents. + * + * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of + * {@link ActivityManagerService} lock since there can be direct calls into this class from outside + * AM. This helps avoid deadlocks. + */ +public class PendingIntentController { + private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; + private static final String TAG_MU = TAG + POSTFIX_MU; + + /** Lock for internal state. */ + final Object mLock = new Object(); + final Handler mH; + ActivityManagerInternal mAmInternal; + final UserController mUserController; + final ActivityTaskManagerInternal mAtmInternal; + + /** Set of IntentSenderRecord objects that are currently active. */ + final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords + = new HashMap<>(); + + PendingIntentController(Looper looper, UserController userController) { + mH = new Handler(looper); + mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); + mUserController = userController; + } + + void onActivityManagerInternalAdded() { + synchronized (mLock) { + mAmInternal = LocalServices.getService(ActivityManagerInternal.class); + } + } + + PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId, + IBinder token, String resultWho, int requestCode, Intent[] intents, + String[] resolvedTypes, int flags, Bundle bOptions) { + synchronized (mLock) { + if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid); + + // We're going to be splicing together extras before sending, so we're + // okay poking into any contained extras. + if (intents != null) { + for (int i = 0; i < intents.length; i++) { + intents[i].setDefusable(true); + } + } + Bundle.setDefusable(bOptions, true); + + final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; + final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0; + final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0; + flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT + | PendingIntent.FLAG_UPDATE_CURRENT); + + PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token, + resultWho, requestCode, intents, resolvedTypes, flags, + SafeActivityOptions.fromBundle(bOptions), userId); + WeakReference<PendingIntentRecord> ref; + ref = mIntentSenderRecords.get(key); + PendingIntentRecord rec = ref != null ? ref.get() : null; + if (rec != null) { + if (!cancelCurrent) { + if (updateCurrent) { + if (rec.key.requestIntent != null) { + rec.key.requestIntent.replaceExtras(intents != null ? + intents[intents.length - 1] : null); + } + if (intents != null) { + intents[intents.length - 1] = rec.key.requestIntent; + rec.key.allIntents = intents; + rec.key.allResolvedTypes = resolvedTypes; + } else { + rec.key.allIntents = null; + rec.key.allResolvedTypes = null; + } + } + return rec; + } + makeIntentSenderCanceled(rec); + mIntentSenderRecords.remove(key); + } + if (noCreate) { + return rec; + } + rec = new PendingIntentRecord(this, key, callingUid); + mIntentSenderRecords.put(key, rec.ref); + return rec; + } + } + + boolean removePendingIntentsForPackage(String packageName, int userId, int appId, + boolean doIt) { + + boolean didSomething = false; + synchronized (mLock) { + + // Remove pending intents. For now we only do this when force stopping users, because + // we have some problems when doing this for packages -- app widgets are not currently + // cleaned up for such packages, so they can be left with bad pending intents. + if (mIntentSenderRecords.size() <= 0) { + return false; + } + + Iterator<WeakReference<PendingIntentRecord>> it + = mIntentSenderRecords.values().iterator(); + while (it.hasNext()) { + WeakReference<PendingIntentRecord> wpir = it.next(); + if (wpir == null) { + it.remove(); + continue; + } + PendingIntentRecord pir = wpir.get(); + if (pir == null) { + it.remove(); + continue; + } + if (packageName == null) { + // Stopping user, remove all objects for the user. + if (pir.key.userId != userId) { + // Not the same user, skip it. + continue; + } + } else { + if (UserHandle.getAppId(pir.uid) != appId) { + // Different app id, skip it. + continue; + } + if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { + // Different user, skip it. + continue; + } + if (!pir.key.packageName.equals(packageName)) { + // Different package, skip it. + continue; + } + } + if (!doIt) { + return true; + } + didSomething = true; + it.remove(); + makeIntentSenderCanceled(pir); + if (pir.key.activity != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::clearPendingResultForActivity, this, + pir.key.activity, pir.ref); + mH.sendMessage(m); + } + } + } + + return didSomething; + } + + public void cancelIntentSender(IIntentSender sender) { + if (!(sender instanceof PendingIntentRecord)) { + return; + } + synchronized (mLock) { + final PendingIntentRecord rec = (PendingIntentRecord) sender; + try { + final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, + MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); + if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { + String msg = "Permission Denial: cancelIntentSender() from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " is not allowed to cancel package " + rec.key.packageName; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } catch (RemoteException e) { + throw new SecurityException(e); + } + cancelIntentSender(rec, true); + } + } + + public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) { + synchronized (mLock) { + makeIntentSenderCanceled(rec); + mIntentSenderRecords.remove(rec.key); + if (cleanActivity && rec.key.activity != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::clearPendingResultForActivity, this, + rec.key.activity, rec.ref); + mH.sendMessage(m); + } + } + } + + private void makeIntentSenderCanceled(PendingIntentRecord rec) { + rec.canceled = true; + final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); + if (callbacks != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::handlePendingIntentCancelled, this, callbacks); + mH.sendMessage(m); + } + } + + private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) { + int N = callbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + try { + callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); + } catch (RemoteException e) { + // Process is not longer running...whatever. + } + } + callbacks.finishBroadcast(); + // We have to clean up the RemoteCallbackList here, because otherwise it will + // needlessly hold the enclosed callbacks until the remote process dies. + callbacks.kill(); + } + + private void clearPendingResultForActivity(IBinder activityToken, + WeakReference<PendingIntentRecord> pir) { + mAtmInternal.clearPendingResultForActivity(activityToken, pir); + } + + void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) { + synchronized (mLock) { + boolean printed = false; + + pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); + + if (mIntentSenderRecords.size() > 0) { + // Organize these by package name, so they are easier to read. + final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); + final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); + final Iterator<WeakReference<PendingIntentRecord>> it + = mIntentSenderRecords.values().iterator(); + while (it.hasNext()) { + WeakReference<PendingIntentRecord> ref = it.next(); + PendingIntentRecord rec = ref != null ? ref.get() : null; + if (rec == null) { + weakRefs.add(ref); + continue; + } + if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { + continue; + } + ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); + if (list == null) { + list = new ArrayList<>(); + byPackage.put(rec.key.packageName, list); + } + list.add(rec); + } + for (int i = 0; i < byPackage.size(); i++) { + ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); + printed = true; + pw.print(" * "); pw.print(byPackage.keyAt(i)); + pw.print(": "); pw.print(intents.size()); pw.println(" items"); + for (int j = 0; j < intents.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); + if (dumpAll) { + intents.get(j).dump(pw, " "); + } + } + } + if (weakRefs.size() > 0) { + printed = true; + pw.println(" * WEAK REFS:"); + for (int i = 0; i < weakRefs.size(); i++) { + pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); + } + } + } + + if (!printed) { + pw.println(" (nothing)"); + } + } + } +} diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index ee1166e2a6e8..b9c6fa6020c4 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -38,15 +38,16 @@ import android.util.Slog; import android.util.TimeUtils; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.Objects; -final class PendingIntentRecord extends IIntentSender.Stub { +public final class PendingIntentRecord extends IIntentSender.Stub { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; - final ActivityManagerService owner; + final PendingIntentController controller; final Key key; final int uid; final WeakReference<PendingIntentRecord> ref; @@ -62,7 +63,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { final static class Key { final int type; final String packageName; - final ActivityRecord activity; + final IBinder activity; final String who; final int requestCode; final Intent requestIntent; @@ -76,7 +77,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { private static final int ODD_PRIME_NUMBER = 37; - Key(int _t, String _p, ActivityRecord _a, String _w, + Key(int _t, String _p, IBinder _a, String _w, int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) { type = _t; packageName = _p; @@ -114,6 +115,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { // + Integer.toHexString(hashCode)); } + @Override public boolean equals(Object otherObj) { if (otherObj == null) { return false; @@ -188,11 +190,11 @@ final class PendingIntentRecord extends IIntentSender.Stub { } } - PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { - owner = _owner; + PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) { + controller = _controller; key = _k; uid = _u; - ref = new WeakReference<PendingIntentRecord>(this); + ref = new WeakReference<>(this); } void setWhitelistDurationLocked(IBinder whitelistToken, long duration) { @@ -247,189 +249,196 @@ final class PendingIntentRecord extends IIntentSender.Stub { } int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, - IIntentReceiver finishedReceiver, - String requiredPermission, IBinder resultTo, String resultWho, int requestCode, - int flagsMask, int flagsValues, Bundle options) { + IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, + String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) { if (intent != null) intent.setDefusable(true); if (options != null) options.setDefusable(true); - synchronized (owner) { - if (!canceled) { - sent = true; - if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { - owner.cancelIntentSenderLocked(this, true); - } + Long duration = null; + Intent finalIntent = null; + Intent[] allIntents = null; + String[] allResolvedTypes = null; + SafeActivityOptions mergedOptions = null; + synchronized (controller.mLock) { + if (canceled) { + return ActivityManager.START_CANCELED; + } - Intent finalIntent = key.requestIntent != null - ? new Intent(key.requestIntent) : new Intent(); + sent = true; + if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) { + controller.cancelIntentSender(this, true); + } - final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; - if (!immutable) { - if (intent != null) { - int changes = finalIntent.fillIn(intent, key.flags); - if ((changes & Intent.FILL_IN_DATA) == 0) { - resolvedType = key.requestResolvedType; - } - } else { + finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); + + final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; + if (!immutable) { + if (intent != null) { + int changes = finalIntent.fillIn(intent, key.flags); + if ((changes & Intent.FILL_IN_DATA) == 0) { resolvedType = key.requestResolvedType; } - flagsMask &= ~Intent.IMMUTABLE_FLAGS; - flagsValues &= flagsMask; - finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); } else { resolvedType = key.requestResolvedType; } + flagsMask &= ~Intent.IMMUTABLE_FLAGS; + flagsValues &= flagsMask; + finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); + } else { + resolvedType = key.requestResolvedType; + } - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); + // Extract options before clearing calling identity + mergedOptions = key.options; + if (mergedOptions == null) { + mergedOptions = SafeActivityOptions.fromBundle(options); + } else { + mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); + } - // Extract options before clearing calling identity - SafeActivityOptions mergedOptions = key.options; - if (mergedOptions == null) { - mergedOptions = SafeActivityOptions.fromBundle(options); - } else { - mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); + if (whitelistDuration != null) { + duration = whitelistDuration.get(whitelistToken); + } + + if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY + && key.allIntents != null && key.allIntents.length > 1) { + // Copy all intents and resolved types while we have the controller lock so we can + // use it later when the lock isn't held. + allIntents = new Intent[key.allIntents.length]; + allResolvedTypes = new String[key.allIntents.length]; + System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length); + if (key.allResolvedTypes != null) { + System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, + key.allResolvedTypes.length); } + allIntents[allIntents.length - 1] = finalIntent; + allResolvedTypes[allResolvedTypes.length - 1] = resolvedType; + } - final long origId = Binder.clearCallingIdentity(); - - if (whitelistDuration != null) { - Long duration = whitelistDuration.get(whitelistToken); - if (duration != null) { - int procState = owner.getUidState(callingUid); - if (!ActivityManager.isProcStateBackground(procState)) { - StringBuilder tag = new StringBuilder(64); - tag.append("pendingintent:"); - UserHandle.formatUid(tag, callingUid); - tag.append(":"); - if (finalIntent.getAction() != null) { - tag.append(finalIntent.getAction()); - } else if (finalIntent.getComponent() != null) { - finalIntent.getComponent().appendShortString(tag); - } else if (finalIntent.getData() != null) { - tag.append(finalIntent.getData().toSafeString()); - } - owner.tempWhitelistForPendingIntentLocked(callingPid, - callingUid, uid, duration, tag.toString()); - } else { - Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" - + procState); - } + } + // We don't hold the controller lock beyond this point as we will be calling into AM and WM. + + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final long origId = Binder.clearCallingIdentity(); + + int res = START_SUCCESS; + try { + if (duration != null) { + int procState = controller.mAmInternal.getUidProcessState(callingUid); + if (!ActivityManager.isProcStateBackground(procState)) { + StringBuilder tag = new StringBuilder(64); + tag.append("pendingintent:"); + UserHandle.formatUid(tag, callingUid); + tag.append(":"); + if (finalIntent.getAction() != null) { + tag.append(finalIntent.getAction()); + } else if (finalIntent.getComponent() != null) { + finalIntent.getComponent().appendShortString(tag); + } else if (finalIntent.getData() != null) { + tag.append(finalIntent.getData().toSafeString()); } + controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid, + uid, duration, tag.toString()); + } else { + Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" + procState); } + } - boolean sendFinish = finishedReceiver != null; - int userId = key.userId; - if (userId == UserHandle.USER_CURRENT) { - userId = owner.mUserController.getCurrentOrTargetUserId(); - } - int res = START_SUCCESS; - switch (key.type) { - case ActivityManager.INTENT_SENDER_ACTIVITY: - try { - // Note when someone has a pending intent, even from different - // users, then there's no need to ensure the calling user matches - // the target user, so validateIncomingUser is always false below. - - if (key.allIntents != null && key.allIntents.length > 1) { - Intent[] allIntents = new Intent[key.allIntents.length]; - String[] allResolvedTypes = new String[key.allIntents.length]; - System.arraycopy(key.allIntents, 0, allIntents, 0, - key.allIntents.length); - if (key.allResolvedTypes != null) { - System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, - key.allResolvedTypes.length); - } - allIntents[allIntents.length-1] = finalIntent; - allResolvedTypes[allResolvedTypes.length-1] = resolvedType; - - res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage( - uid, key.packageName, allIntents, allResolvedTypes, - resultTo, mergedOptions, userId, - false /* validateIncomingUser */, - this /* originatingPendingIntent */); - } else { - res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid, - callingPid, callingUid, key.packageName, finalIntent, - resolvedType, resultTo, resultWho, requestCode, 0, - mergedOptions, userId, null, "PendingIntentRecord", - false /* validateIncomingUser */, - this /* originatingPendingIntent */); - } - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startActivity intent", e); - } - break; - case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: - final ActivityStack stack = key.activity.getStack(); - if (stack != null) { - stack.sendActivityResultLocked(-1, key.activity, key.who, - key.requestCode, code, finalIntent); - } - break; - case ActivityManager.INTENT_SENDER_BROADCAST: - try { - // If a completion callback has been requested, require - // that the broadcast be delivered synchronously - int sent = owner.broadcastIntentInPackage(key.packageName, uid, - finalIntent, resolvedType, finishedReceiver, code, null, null, - requiredPermission, options, (finishedReceiver != null), - false, userId); - if (sent == ActivityManager.BROADCAST_SUCCESS) { - sendFinish = false; - } - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startActivity intent", e); + boolean sendFinish = finishedReceiver != null; + int userId = key.userId; + if (userId == UserHandle.USER_CURRENT) { + userId = controller.mUserController.getCurrentOrTargetUserId(); + } + + switch (key.type) { + case ActivityManager.INTENT_SENDER_ACTIVITY: + try { + // Note when someone has a pending intent, even from different + // users, then there's no need to ensure the calling user matches + // the target user, so validateIncomingUser is always false below. + + if (key.allIntents != null && key.allIntents.length > 1) { + res = controller.mAtmInternal.startActivitiesInPackage( + uid, key.packageName, allIntents, allResolvedTypes, resultTo, + mergedOptions, userId, false /* validateIncomingUser */, + this /* originatingPendingIntent */); + } else { + res = controller.mAtmInternal.startActivityInPackage( + uid, callingPid, callingUid, key.packageName, finalIntent, + resolvedType, resultTo, resultWho, requestCode, 0, + mergedOptions, userId, null, "PendingIntentRecord", + false /* validateIncomingUser */, + this /* originatingPendingIntent */); } - break; - case ActivityManager.INTENT_SENDER_SERVICE: - case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: - try { - owner.startServiceInPackage(uid, finalIntent, resolvedType, - key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, - key.packageName, userId); - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startService intent", e); - } catch (TransactionTooLargeException e) { - res = ActivityManager.START_CANCELED; + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who, + key.requestCode, code, finalIntent); + break; + case ActivityManager.INTENT_SENDER_BROADCAST: + try { + // If a completion callback has been requested, require + // that the broadcast be delivered synchronously + int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName, + uid, finalIntent, resolvedType, finishedReceiver, code, null, null, + requiredPermission, options, (finishedReceiver != null), + false, userId); + if (sent == ActivityManager.BROADCAST_SUCCESS) { + sendFinish = false; } - break; - } - - if (sendFinish && res != ActivityManager.START_CANCELED) { + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_SERVICE: + case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: try { - finishedReceiver.performReceive(new Intent(finalIntent), 0, - null, null, false, false, key.userId); - } catch (RemoteException e) { + controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType, + key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, + key.packageName, userId); + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startService intent", e); + } catch (TransactionTooLargeException e) { + res = ActivityManager.START_CANCELED; } - } - - Binder.restoreCallingIdentity(origId); + break; + } - return res; + if (sendFinish && res != ActivityManager.START_CANCELED) { + try { + finishedReceiver.performReceive(new Intent(finalIntent), 0, + null, null, false, false, key.userId); + } catch (RemoteException e) { + } } + } finally { + Binder.restoreCallingIdentity(origId); } - return ActivityManager.START_CANCELED; + + return res; } @Override protected void finalize() throws Throwable { try { if (!canceled) { - owner.mHandler.sendMessage(owner.mHandler.obtainMessage( - ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); + controller.mH.sendMessage(PooledLambda.obtainMessage( + PendingIntentRecord::completeFinalize, this)); } } finally { super.finalize(); } } - public void completeFinalize() { - synchronized(owner) { - WeakReference<PendingIntentRecord> current = - owner.mIntentSenderRecords.get(key); + private void completeFinalize() { + synchronized(controller.mLock) { + WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key); if (current == ref) { - owner.mIntentSenderRecords.remove(key); + controller.mIntentSenderRecords.remove(key); } } } diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java index f7de7f475b7b..fa0cb47ade02 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -44,7 +44,7 @@ import com.android.internal.annotations.VisibleForTesting; * the inner options. Also supports having two set of options: Once from the original caller, and * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. */ -class SafeActivityOptions { +public class SafeActivityOptions { private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 9b42d65483df..ef8cb1c07969 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -129,7 +129,8 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; -class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { +// TODO: Make package private again once move to WM package is complete. +public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java new file mode 100644 index 000000000000..91b3b21632c6 --- /dev/null +++ b/services/core/java/com/android/server/appbinding/AppBindingService.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appbinding; + +import android.app.AppGlobals; +import android.content.Context; +import android.content.pm.IPackageManager; +import android.os.Binder; +import android.os.Handler; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.DumpUtils; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * System server that keeps a binding to an app to keep it always running. + */ +public class AppBindingService extends Binder { + public static final String TAG = "AppBindingService"; + + private static final boolean DEBUG = false; + + private final Object mLock = new Object(); + + private final Injector mInjector; + private final Context mContext; + private final Handler mHandler; + private final IPackageManager mIPackageManager; + + static class Injector { + public IPackageManager getIPackageManager() { + return AppGlobals.getPackageManager(); + } + } + + /** + * System service interacts with this service via this class. + */ + public static final class Lifecycle extends SystemService { + final AppBindingService mService; + + public Lifecycle(Context context) { + super(context); + mService = new AppBindingService(new Injector(), context); + } + + @Override + public void onStart() { + publishBinderService(Context.APP_BINDING_SERVICE, mService); + } + } + + private AppBindingService(Injector injector, Context context) { + mInjector = injector; + mContext = context; + mIPackageManager = injector.getIPackageManager(); + mHandler = BackgroundThread.getHandler(); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + } +} diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8caa70283acf..66c7c437284b 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -627,6 +627,13 @@ public class AudioService extends IAudioService.Stub // If absolute volume is supported in AVRCP device private boolean mAvrcpAbsVolSupported = false; + // Pre-scale for Bluetooth Absolute Volume + private float[] mPrescaleAbsoluteVolume = new float[] { + 0.5f, // Pre-scale for index 1 + 0.7f, // Pre-scale for index 2 + 0.85f, // Pre-scale for index 3 + }; + private static Long mLastDeviceConnectMsgTime = new Long(0); private NotificationManager mNm; @@ -878,6 +885,23 @@ public class AudioService extends IAudioService.Stub mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); mRecordMonitor.initMonitor(); + + final float[] preScale = new float[3]; + preScale[0] = mContext.getResources().getFraction( + com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1, + 1, 1); + preScale[1] = mContext.getResources().getFraction( + com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2, + 1, 1); + preScale[2] = mContext.getResources().getFraction( + com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3, + 1, 1); + for (int i = 0; i < preScale.length; i++) { + if (0.0f <= preScale[i] && preScale[i] <= 1.0f) { + mPrescaleAbsoluteVolume[i] = preScale[i]; + } + } + } public void systemReady() { @@ -4926,18 +4950,12 @@ public class AudioService extends IAudioService.Stub if (index == 0) { // 0% for volume 0 index = 0; - } else if (index == 1) { - // 50% for volume 1 - index = (int)(mIndexMax * 0.5) /10; - } else if (index == 2) { - // 70% for volume 2 - index = (int)(mIndexMax * 0.70) /10; - } else if (index == 3) { - // 85% for volume 3 - index = (int)(mIndexMax * 0.85) /10; + } else if (index > 0 && index <= 3) { + // Pre-scale for volume steps 1 2 and 3 + index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10; } else { // otherwise, full gain - index = (mIndexMax + 5)/10; + index = (mIndexMax + 5) / 10; } return index; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index deeae26d034c..2557f46ba34b 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2828,7 +2828,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Assumes it's safe to show starting windows of launched apps while // the keyguard is being hidden. This is okay because starting windows never show // secret information. - if (mKeyguardOccluded) { + // TODO(b/113840485): Occluded may not only happen on default display + if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) { windowFlags |= FLAG_SHOW_WHEN_LOCKED; } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 68e636a2afc2..5adc248cee79 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -190,6 +190,8 @@ public class Notifier { try { mBatteryStats.noteInteractive(true); } catch (RemoteException ex) { } + StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED, + StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON); } /** @@ -401,6 +403,9 @@ public class Notifier { try { mBatteryStats.noteInteractive(interactive); } catch (RemoteException ex) { } + StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED, + interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON : + StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF); // Handle early behaviors. mInteractive = interactive; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d2fc15a28c5..bcf9212464db 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -22,6 +22,7 @@ import android.app.AppProtoEnums; import android.app.IActivityManager; import android.app.IApplicationThread; import android.content.ComponentName; +import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; @@ -32,8 +33,12 @@ import android.service.voice.IVoiceInteractionSession; import android.util.SparseIntArray; import com.android.internal.app.IVoiceInteractor; +import com.android.server.am.PendingIntentRecord; +import com.android.server.am.SafeActivityOptions; +import com.android.server.am.TaskRecord; import com.android.server.am.WindowProcessController; +import java.lang.ref.WeakReference; import java.util.List; /** @@ -178,6 +183,27 @@ public abstract class ActivityTaskManagerInternal { int userId, Intent[] intents, Bundle bOptions); /** + * Start intents as a package. + * + * @param uid Make a call as if this UID did. + * @param callingPackage Make a call as if this package did. + * @param intents Intents to start. + * @param userId Start the intents on this user. + * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID. + * @param originatingPendingIntent PendingIntentRecord that originated this activity start or + * null if not originated by PendingIntent + */ + public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, + String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent); + + public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, + String callingPackage, Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, SafeActivityOptions options, + int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, + PendingIntentRecord originatingPendingIntent); + + /** * Start activity {@code intent} without calling user-id check. * * - DO NOT call it with the calling UID cleared. @@ -297,4 +323,13 @@ public abstract class ActivityTaskManagerInternal { * @param displayId The ID of the display showing the IME. */ public abstract void onImeWindowSetOnDisplay(int pid, int displayId); + + public abstract void sendActivityResult(int callingUid, IBinder activityToken, + String resultWho, int requestCode, int resultCode, Intent data); + public abstract void clearPendingResultForActivity( + IBinder activityToken, WeakReference<PendingIntentRecord> pir); + public abstract IIntentSender getIntentSender(int type, String packageName, + int callingUid, int userId, IBinder token, String resultWho, + int requestCode, Intent[] intents, String[] resolvedTypes, int flags, + Bundle bOptions); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index d92818ac611c..a9571be9599d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -48,7 +48,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SU import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE; import static com.android.server.wm.WindowManagerService.logSurface; -import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION; import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING; @@ -91,7 +90,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1; private static final int SET_USER_ACTIVITY_TIMEOUT = 2; - private boolean mWallpaperForceHidingChanged = false; private Object mLastWindowFreezeSource = null; private Session mHoldScreen = null; private float mScreenBrightness = -1; @@ -626,18 +624,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { recentsAnimationController.checkAnimationReady(mWallpaperController); } - if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0 - && !mService.mAppTransition.isReady()) { - // At this point, there was a window with a wallpaper that was force hiding other - // windows behind it, but now it is going away. This may be simple -- just animate away - // the wallpaper and its window -- or it may be hard -- the wallpaper now needs to be - // shown behind something that was hidden. - defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT; - if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats( - "after animateAwayWallpaperLocked", defaultDisplay.pendingLayoutChanges); - } - mWallpaperForceHidingChanged = false; - if (mWallpaperMayChange) { if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change! Adjusting"); defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -961,10 +947,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { mWallpaperMayChange = true; doRequest = true; } - if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) { - mWallpaperForceHidingChanged = true; - doRequest = true; - } if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) { mOrientationChangeComplete = false; } else { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 793ffce2466e..a1d6ffd0249e 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -284,9 +284,6 @@ public class WindowAnimator { if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) { builder.append(" WALLPAPER_MAY_CHANGE"); } - if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) { - builder.append(" FORCE_HIDING_CHANGED"); - } if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) { builder.append(" ORIENTATION_CHANGE_COMPLETE"); } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index d6f9ac3a3ab9..c8d1a8b14e82 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -92,9 +92,8 @@ class WindowSurfacePlacer { static final int SET_UPDATE_ROTATION = 1 << 0; static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1; - static final int SET_FORCE_HIDING_CHANGED = 1 << 2; - static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 3; - static final int SET_WALLPAPER_ACTION_PENDING = 1 << 4; + static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 2; + static final int SET_WALLPAPER_ACTION_PENDING = 1 << 3; private boolean mTraversalScheduled; private int mDeferDepth = 0; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index fb95f5972cbb..b8241d03a78e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -65,6 +65,7 @@ import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.widget.ILockSettings; import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityTaskManagerService; +import com.android.server.appbinding.AppBindingService; import com.android.server.audio.AudioService; import com.android.server.biometrics.BiometricService; import com.android.server.broadcastradio.BroadcastRadioService; @@ -1710,6 +1711,10 @@ public final class SystemServer { traceEnd(); } + traceBeginAndSlog("AppServiceManager"); + mSystemServiceManager.startService(AppBindingService.Lifecycle.class); + traceEnd(); + // It is now time to start up the app processes... traceBeginAndSlog("MakeVibratorServiceReady"); diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index 8b5977144db1..78c0be42a448 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \ $(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \ $(call all-java-files-under, ../../core/java/android/app/backup) \ $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \ + $(call all-java-files-under, ../../core/java/android/util/proto) \ ../../core/java/android/content/pm/PackageInfo.java \ ../../core/java/android/app/IBackupAgent.aidl \ ../../core/java/android/util/KeyValueSettingObserver.java \ diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java new file mode 100644 index 000000000000..383bf1d73416 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +import com.android.internal.util.Preconditions; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.base.Charsets; +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +// Include android.util.proto in addition to classes under test because the latest versions of +// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric. +@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"}) +@Presubmit +public class ChunkListingTest { + private static final String CHUNK_A = "CHUNK_A"; + private static final String CHUNK_B = "CHUNK_B"; + private static final String CHUNK_C = "CHUNK_C"; + + private static final int CHUNK_A_LENGTH = 256; + private static final int CHUNK_B_LENGTH = 1024; + private static final int CHUNK_C_LENGTH = 4055; + + private ChunkHash mChunkHashA; + private ChunkHash mChunkHashB; + private ChunkHash mChunkHashC; + + @Before + public void setUp() throws Exception { + mChunkHashA = getHash(CHUNK_A); + mChunkHashB = getHash(CHUNK_B); + mChunkHashC = getHash(CHUNK_C); + } + + @Test + public void testHasChunk_whenChunkInListing_returnsTrue() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + + boolean chunkAInList = chunkListing.hasChunk(mChunkHashA); + boolean chunkBInList = chunkListing.hasChunk(mChunkHashB); + boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + + assertThat(chunkAInList).isTrue(); + assertThat(chunkBInList).isTrue(); + assertThat(chunkCInList).isTrue(); + } + + @Test + public void testHasChunk_whenChunkNotInListing_returnsFalse() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + ChunkHash chunkHashEmpty = getHash(""); + + boolean chunkCInList = chunkListing.hasChunk(mChunkHashC); + boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty); + + assertThat(chunkCInList).isFalse(); + assertThat(emptyChunkInList).isFalse(); + } + + @Test + public void testGetChunkEntry_returnsEntryWithCorrectLength() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + + ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); + ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); + ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + + assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH); + assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH); + assertThat(entryC.getLength()).isEqualTo(CHUNK_C_LENGTH); + } + + @Test + public void testGetChunkEntry_returnsEntryWithCorrectStart() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + + ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA); + ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB); + ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC); + + assertThat(entryA.getStart()).isEqualTo(0); + assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH); + assertThat(entryC.getStart()).isEqualTo(CHUNK_A_LENGTH + CHUNK_B_LENGTH); + } + + @Test + public void testGetChunkEntry_returnsNullForNonExistentChunk() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH}); + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + + ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC); + + assertThat(chunkEntryNonexistentChunk).isNull(); + } + + @Test + public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception { + ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); + + ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto); + + assertThat(chunkListing.getChunkCount()).isEqualTo(0); + } + + @Test + public void testReadFromProto_returnsChunkListingWithCorrectSize() throws Exception { + byte[] chunkListingProto = + createChunkListingProto( + new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC}, + new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH}); + + ChunkListing chunkListing = + ChunkListing.readFromProto( + new ProtoInputStream(new ByteArrayInputStream(chunkListingProto))); + + assertThat(chunkListing.getChunkCount()).isEqualTo(3); + } + + private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) { + Preconditions.checkArgument(hashes.length == lengths.length); + ProtoOutputStream outputStream = new ProtoOutputStream(); + + for (int i = 0; i < hashes.length; ++i) { + writeToProtoOutputStream(outputStream, hashes[i], lengths[i]); + } + outputStream.flush(); + + return outputStream.getBytes(); + } + + private void writeToProtoOutputStream(ProtoOutputStream out, ChunkHash chunkHash, int length) { + long token = out.start(ChunksMetadataProto.ChunkListing.CHUNKS); + out.write(ChunksMetadataProto.Chunk.HASH, chunkHash.getHash()); + out.write(ChunksMetadataProto.Chunk.LENGTH, length); + out.end(token); + } + + private ChunkHash getHash(String name) { + return new ChunkHash( + Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES)); + } +} diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java new file mode 100644 index 000000000000..1dd7dc834f9e --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.base.Charsets; +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +// Include android.util.proto in addition to classes under test because the latest versions of +// android.util.proto.Proto{Input|Output}Stream are not part of Robolectric. +@SystemLoaderPackages({"com.android.server.backup", "android.util.proto"}) +@Presubmit +public class ChunkTest { + private static final String CHUNK_A = "CHUNK_A"; + private static final int CHUNK_A_LENGTH = 256; + + private ChunkHash mChunkHashA; + + @Before + public void setUp() throws Exception { + mChunkHashA = getHash(CHUNK_A); + } + + @Test + public void testReadFromProto_readsCorrectly() throws Exception { + ProtoOutputStream out = new ProtoOutputStream(); + out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); + out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); + out.flush(); + byte[] protoBytes = out.getBytes(); + + Chunk chunk = + Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + + assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); + assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); + } + + @Test + public void testReadFromProto_whenFieldsWrittenInReversedOrder_readsCorrectly() + throws Exception { + ProtoOutputStream out = new ProtoOutputStream(); + // Write fields of Chunk proto in reverse order. + out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); + out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); + out.flush(); + byte[] protoBytes = out.getBytes(); + + Chunk chunk = + Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + + assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); + assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); + } + + @Test + public void testReadFromProto_whenEmptyProto_returnsEmptyHash() throws Exception { + ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {})); + + Chunk chunk = Chunk.readFromProto(emptyProto); + + assertThat(chunk.getHash()).asList().hasSize(0); + assertThat(chunk.getLength()).isEqualTo(0); + } + + @Test + public void testReadFromProto_whenOnlyHashSet_returnsChunkWithOnlyHash() throws Exception { + ProtoOutputStream out = new ProtoOutputStream(); + out.write(ChunksMetadataProto.Chunk.HASH, mChunkHashA.getHash()); + out.flush(); + byte[] protoBytes = out.getBytes(); + + Chunk chunk = + Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + + assertThat(chunk.getHash()).isEqualTo(mChunkHashA.getHash()); + assertThat(chunk.getLength()).isEqualTo(0); + } + + @Test + public void testReadFromProto_whenOnlyLengthSet_returnsChunkWithOnlyLength() throws Exception { + ProtoOutputStream out = new ProtoOutputStream(); + out.write(ChunksMetadataProto.Chunk.LENGTH, CHUNK_A_LENGTH); + out.flush(); + byte[] protoBytes = out.getBytes(); + + Chunk chunk = + Chunk.readFromProto(new ProtoInputStream(new ByteArrayInputStream(protoBytes))); + + assertThat(chunk.getHash()).isEqualTo(new byte[] {}); + assertThat(chunk.getLength()).isEqualTo(CHUNK_A_LENGTH); + } + + private ChunkHash getHash(String name) { + return new ChunkHash( + Arrays.copyOf(name.getBytes(Charsets.UTF_8), ChunkHash.HASH_LENGTH_BYTES)); + } +} diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java new file mode 100644 index 000000000000..1cd1528b930c --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/EncryptedChunkOrderingTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.primitives.Bytes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class EncryptedChunkOrderingTest { + private static final byte[] TEST_BYTE_ARRAY_1 = new byte[] {1, 2, 3, 4, 5}; + private static final byte[] TEST_BYTE_ARRAY_2 = new byte[] {5, 4, 3, 2, 1}; + + @Test + public void testEncryptedChunkOrdering_returnsValue() { + EncryptedChunkOrdering encryptedChunkOrdering = + EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + + byte[] bytes = encryptedChunkOrdering.encryptedChunkOrdering(); + + assertThat(bytes) + .asList() + .containsExactlyElementsIn(Bytes.asList(TEST_BYTE_ARRAY_1)) + .inOrder(); + } + + @Test + public void testEquals() { + EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + EncryptedChunkOrdering equalChunkOrdering1 = + EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2); + + assertThat(chunkOrdering1).isEqualTo(equalChunkOrdering1); + assertThat(chunkOrdering1).isNotEqualTo(chunkOrdering2); + } + + @Test + public void testHashCode() { + EncryptedChunkOrdering chunkOrdering1 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + EncryptedChunkOrdering equalChunkOrdering1 = + EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_1); + EncryptedChunkOrdering chunkOrdering2 = EncryptedChunkOrdering.create(TEST_BYTE_ARRAY_2); + + int hash1 = chunkOrdering1.hashCode(); + int equalHash1 = equalChunkOrdering1.hashCode(); + int hash2 = chunkOrdering2.hashCode(); + + assertThat(hash1).isEqualTo(equalHash1); + assertThat(hash1).isNotEqualTo(hash2); + } +} diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 777b850bc9c5..38ee79f06690 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1852,6 +1852,19 @@ public class SubscriptionManager { } /** + * Checks if the supplied subscription ID corresponds to an active subscription. + * + * @param subscriptionId the subscription ID. + * @return {@code true} if the supplied subscription ID corresponds to an active subscription; + * {@code false} if it does not correspond to an active subscription; or throw a + * SecurityException if the caller hasn't got the right permission. + */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public boolean isActiveSubscriptionId(int subscriptionId) { + return isActiveSubId(subscriptionId); + } + + /** * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription * and the SIM providing the subscription is present in a slot and in "LOADED" state. * @hide @@ -1861,7 +1874,7 @@ public class SubscriptionManager { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); if (iSub != null) { - return iSub.isActiveSubId(subId); + return iSub.isActiveSubId(subId, mContext.getOpPackageName()); } } catch (RemoteException ex) { } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d58b932f2851..824533d59bf5 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,6 +16,8 @@ package android.telephony; +import static android.content.Context.TELECOM_SERVICE; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; @@ -1201,6 +1203,15 @@ public class TelephonyManager { "android.intent.action.DATA_STALL_DETECTED"; /** + * A service action that identifies a {@link android.app.SmsAppService} subclass in the + * AndroidManifest.xml. + * + * <p>See {@link android.app.SmsAppService} for the details. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE"; + + /** * An int extra used with {@link #ACTION_DATA_STALL_DETECTED} to indicate the * action associated with the data stall recovery. * @@ -4372,7 +4383,7 @@ public class TelephonyManager { * @hide */ private ITelecomService getTelecomService() { - return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE)); + return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE)); } private ITelephonyRegistry getTelephonyRegistry() { @@ -5402,7 +5413,19 @@ public class TelephonyManager { } } - // ICC SIM Application Types + /** + * UICC SIM Application Types + * @hide + */ + @IntDef(prefix = { "APPTYPE_" }, value = { + APPTYPE_SIM, + APPTYPE_USIM, + APPTYPE_RUIM, + APPTYPE_CSIM, + APPTYPE_ISIM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UiccAppType{} /** UICC application type is SIM */ public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM; /** UICC application type is USIM */ @@ -5413,6 +5436,7 @@ public class TelephonyManager { public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM; /** UICC application type is ISIM */ public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM; + // authContext (parameter P2) when doing UICC challenge, // per 3GPP TS 31.102 (Section 7.1.2) /** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */ @@ -5679,6 +5703,202 @@ public class TelephonyManager { } } + /** @hide */ + @IntDef(prefix = { "NETWORK_MODE_" }, value = { + NETWORK_MODE_WCDMA_PREF, + NETWORK_MODE_GSM_ONLY, + NETWORK_MODE_WCDMA_ONLY, + NETWORK_MODE_GSM_UMTS, + NETWORK_MODE_CDMA_EVDO, + NETWORK_MODE_CDMA_NO_EVDO, + NETWORK_MODE_EVDO_NO_CDMA, + NETWORK_MODE_GLOBAL, + NETWORK_MODE_LTE_CDMA_EVDO, + NETWORK_MODE_LTE_GSM_WCDMA, + NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA, + NETWORK_MODE_LTE_ONLY, + NETWORK_MODE_LTE_WCDMA, + NETWORK_MODE_TDSCDMA_ONLY, + NETWORK_MODE_TDSCDMA_WCDMA, + NETWORK_MODE_LTE_TDSCDMA, + NETWORK_MODE_TDSCDMA_GSM, + NETWORK_MODE_LTE_TDSCDMA_GSM, + NETWORK_MODE_TDSCDMA_GSM_WCDMA, + NETWORK_MODE_LTE_TDSCDMA_WCDMA, + NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA, + NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA, + NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrefNetworkMode{} + + /** + * preferred network mode is GSM/WCDMA (WCDMA preferred). + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF; + + /** + * preferred network mode is GSM only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY; + + /** + * preferred network mode is WCDMA only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY; + + /** + * preferred network mode is GSM/WCDMA (auto mode, according to PRL). + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS; + + /** + * preferred network mode is CDMA and EvDo (auto mode, according to PRL). + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA; + + /** + * preferred network mode is CDMA only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO; + + /** + * preferred network mode is EvDo only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA; + + /** + * preferred network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL). + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL; + + /** + * preferred network mode is LTE, CDMA and EvDo. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO; + + /** + * preferred network mode is LTE, GSM/WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA; + + /** + * preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = + RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA; + + /** + * preferred network mode is LTE Only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY; + + /** + * preferred network mode is LTE/WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA; + + /** + * preferred network mode is TD-SCDMA only. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY; + + /** + * preferred network mode is TD-SCDMA and WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA; + + /** + * preferred network mode is TD-SCDMA and LTE. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA; + + /** + * preferred network mode is TD-SCDMA and GSM. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM; + + /** + * preferred network mode is TD-SCDMA,GSM and LTE. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = + RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM; + + /** + * preferred network mode is TD-SCDMA, GSM/WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = + RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA; + + /** + * preferred network mode is TD-SCDMA, WCDMA and LTE. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = + RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA; + + /** + * preferred network mode is TD-SCDMA, GSM/WCDMA and LTE. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = + RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA; + + /** + * preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = + RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; + /** + * preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo. + * @hide + */ + @SystemApi + public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = + RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; + /** * Get the preferred network type. * Used for device configuration by some CDMA operators. @@ -5687,11 +5907,12 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @return the preferred network type, defined in RILConstants.java. + * @return the preferred network type. * @hide */ - @UnsupportedAppUsage - public int getPreferredNetworkType(int subId) { + @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE)) + @SystemApi + public @PrefNetworkMode int getPreferredNetworkType(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) @@ -6273,7 +6494,7 @@ public class TelephonyManager { } /** - * @deprecated Use {@link android.telecom.TelecomManager#endCall()} instead. + * @removed Use {@link android.telecom.TelecomManager#endCall()} instead. * @hide * @removed */ @@ -6285,7 +6506,7 @@ public class TelephonyManager { } /** - * @deprecated Use {@link android.telecom.TelecomManager#acceptRingingCall} instead + * @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead * @hide * @removed */ @@ -6293,26 +6514,22 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void answerRingingCall() { - + // No-op } /** - * @deprecated Use {@link android.telecom.TelecomManager#silenceRinger} instead + * @removed Use {@link android.telecom.TelecomManager#silenceRinger} instead * @hide */ @Deprecated @SystemApi @SuppressLint("Doclava125") public void silenceRinger() { - try { - getTelecomService().silenceRinger(getOpPackageName()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelecomService#silenceRinger", e); - } + // No-op } /** - * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead + * @removed Use {@link android.telecom.TelecomManager#isInCall} instead * @hide */ @Deprecated @@ -6322,18 +6539,11 @@ public class TelephonyManager { android.Manifest.permission.READ_PHONE_STATE }) public boolean isOffhook() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.isOffhook(getOpPackageName()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#isOffhook", e); - } return false; } /** - * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead + * @removed Use {@link android.telecom.TelecomManager#isRinging} instead * @hide */ @Deprecated @@ -6343,18 +6553,11 @@ public class TelephonyManager { android.Manifest.permission.READ_PHONE_STATE }) public boolean isRinging() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.isRinging(getOpPackageName()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#isRinging", e); - } return false; } /** - * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead + * @removed Use {@link android.telecom.TelecomManager#isInCall} instead * @hide */ @Deprecated @@ -6364,13 +6567,6 @@ public class TelephonyManager { android.Manifest.permission.READ_PHONE_STATE }) public boolean isIdle() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.isIdle(getOpPackageName()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#isIdle", e); - } return true; } @@ -7856,26 +8052,23 @@ public class TelephonyManager { } /** - * Return the application ID for the app type like {@link APPTYPE_CSIM}. - * - * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission + * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}. + * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220 + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} * - * @param appType the uicc app type like {@link APPTYPE_CSIM} - * @return Application ID for specificied app type or null if no uicc or error. + * @param appType the uicc app type. + * @return Application ID for specified app type or {@code null} if no uicc or error. * @hide */ - public String getAidForAppType(int appType) { + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public String getAidForAppType(@UiccAppType int appType) { return getAidForAppType(getSubId(), appType); } /** - * Return the application ID for the app type like {@link APPTYPE_CSIM}. - * - * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission - * - * @param subId the subscription ID that this request applies to. - * @param appType the uicc app type, like {@link APPTYPE_CSIM} - * @return Application ID for specificied app type or null if no uicc or error. + * same as {@link #getAidForAppType(int)} * @hide */ public String getAidForAppType(int subId, int appType) { diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 6521f0b41cb2..0ccd748c31df 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -232,5 +232,5 @@ interface ISub { */ int getSimStateForSlotIndex(int slotIndex); - boolean isActiveSubId(int subId); + boolean isActiveSubId(int subId, String callingPackage); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index e1c770c8deec..ca2bcff2f4cd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -75,116 +75,6 @@ interface ITelephony { void call(String callingPackage, String number); /** - * End call if there is a call in progress, otherwise does nothing. - * - * @return whether it hung up - */ - boolean endCall(); - - /** - * End call on particular subId or go to the Home screen - * @param subId user preferred subId. - * @return whether it hung up - */ - boolean endCallForSubscriber(int subId); - - /** - * Answer the currently-ringing call. - * - * If there's already a current active call, that call will be - * automatically put on hold. If both lines are currently in use, the - * current active call will be ended. - * - * TODO: provide a flag to let the caller specify what policy to use - * if both lines are in use. (The current behavior is hardwired to - * "answer incoming, end ongoing", which is how the CALL button - * is specced to behave.) - * - * TODO: this should be a oneway call (especially since it's called - * directly from the key queue thread). - */ - void answerRingingCall(); - - /** - * Answer the currently-ringing call on particular subId . - * - * If there's already a current active call, that call will be - * automatically put on hold. If both lines are currently in use, the - * current active call will be ended. - * - * TODO: provide a flag to let the caller specify what policy to use - * if both lines are in use. (The current behavior is hardwired to - * "answer incoming, end ongoing", which is how the CALL button - * is specced to behave.) - * - * TODO: this should be a oneway call (especially since it's called - * directly from the key queue thread). - */ - void answerRingingCallForSubscriber(int subId); - - /** - * Silence the ringer if an incoming call is currently ringing. - * (If vibrating, stop the vibrator also.) - * - * It's safe to call this if the ringer has already been silenced, or - * even if there's no incoming call. (If so, this method will do nothing.) - * - * TODO: this should be a oneway call too (see above). - * (Actually *all* the methods here that return void can - * probably be oneway.) - */ - void silenceRinger(); - - /** - * Check if we are in either an active or holding call - * @param callingPackage the name of the package making the call. - * @return true if the phone state is OFFHOOK. - */ - boolean isOffhook(String callingPackage); - - /** - * Check if a particular subId has an active or holding call - * - * @param subId user preferred subId. - * @param callingPackage the name of the package making the call. - * @return true if the phone state is OFFHOOK. - */ - boolean isOffhookForSubscriber(int subId, String callingPackage); - - /** - * Check if an incoming phone call is ringing or call waiting - * on a particular subId. - * - * @param subId user preferred subId. - * @param callingPackage the name of the package making the call. - * @return true if the phone state is RINGING. - */ - boolean isRingingForSubscriber(int subId, String callingPackage); - - /** - * Check if an incoming phone call is ringing or call waiting. - * @param callingPackage the name of the package making the call. - * @return true if the phone state is RINGING. - */ - boolean isRinging(String callingPackage); - - /** - * Check if the phone is idle. - * @param callingPackage the name of the package making the call. - * @return true if the phone state is IDLE. - */ - boolean isIdle(String callingPackage); - - /** - * Check if the phone is idle on a particular subId. - * - * @param subId user preferred subId. - * @param callingPackage the name of the package making the call. - * @return true if the phone state is IDLE. - */ - boolean isIdleForSubscriber(int subId, String callingPackage); - - /** * Check to see if the radio is on or not. * @param callingPackage the name of the package making the call. * @return returns true if the radio is on. diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 4a6fe49f2676..1f60b71c3c0f 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -247,8 +247,14 @@ public class AppLaunch extends InstrumentationTestCase { mIterationCycle = false; // In the "applaunch.txt" file, trail launches is referenced using // "TRIAL_LAUNCH" - String appPkgName = mNameToIntent.get(launch.getApp()) - .getComponent().getPackageName(); + Intent startIntent = mNameToIntent.get(launch.getApp()); + if (startIntent == null) { + Log.w(TAG, "App does not exist: " + launch.getApp()); + mResult.putString(mNameToResultKey.get(launch.getApp()), + "App does not exist"); + continue; + } + String appPkgName = startIntent.getComponent().getPackageName(); if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) { assertTrue(String.format("Not able to compile the app : %s", appPkgName), compileApp(VERIFY_FILTER, appPkgName)); diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp index c0eaa8e08418..7872738320c3 100644 --- a/tools/aapt2/io/FileStream_test.cpp +++ b/tools/aapt2/io/FileStream_test.cpp @@ -41,46 +41,46 @@ TEST(FileInputStreamTest, NextAndBackup) { ASSERT_FALSE(in.HadError()); EXPECT_THAT(in.ByteCount(), Eq(0u)); - const char* buffer; + const void* buffer; size_t size; - ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)) << in.GetError(); + ASSERT_TRUE(in.Next(&buffer, &size)) << in.GetError(); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); EXPECT_THAT(in.ByteCount(), Eq(10u)); - EXPECT_THAT(StringPiece(buffer, size), Eq("this is a ")); + EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("this is a ")); - ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); + ASSERT_TRUE(in.Next(&buffer, &size)); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); EXPECT_THAT(in.ByteCount(), Eq(20u)); - EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin")); + EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin")); in.BackUp(5u); EXPECT_THAT(in.ByteCount(), Eq(15u)); - ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); + ASSERT_TRUE(in.Next(&buffer, &size)); ASSERT_THAT(size, Eq(5u)); ASSERT_THAT(buffer, NotNull()); ASSERT_THAT(in.ByteCount(), Eq(20u)); - EXPECT_THAT(StringPiece(buffer, size), Eq("strin")); + EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("strin")); // Backup 1 more than possible. Should clamp. in.BackUp(11u); EXPECT_THAT(in.ByteCount(), Eq(10u)); - ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); + ASSERT_TRUE(in.Next(&buffer, &size)); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); ASSERT_THAT(in.ByteCount(), Eq(20u)); - EXPECT_THAT(StringPiece(buffer, size), Eq("cool strin")); + EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("cool strin")); - ASSERT_TRUE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); + ASSERT_TRUE(in.Next(&buffer, &size)); ASSERT_THAT(size, Eq(1u)); ASSERT_THAT(buffer, NotNull()); ASSERT_THAT(in.ByteCount(), Eq(21u)); - EXPECT_THAT(StringPiece(buffer, size), Eq("g")); + EXPECT_THAT(StringPiece(reinterpret_cast<const char*>(buffer), size), Eq("g")); - EXPECT_FALSE(in.Next(reinterpret_cast<const void**>(&buffer), &size)); + EXPECT_FALSE(in.Next(&buffer, &size)); EXPECT_FALSE(in.HadError()); } @@ -93,25 +93,25 @@ TEST(FileOutputStreamTest, NextAndBackup) { ASSERT_FALSE(out.HadError()); EXPECT_THAT(out.ByteCount(), Eq(0u)); - char* buffer; + void* buffer; size_t size; - ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); + ASSERT_TRUE(out.Next(&buffer, &size)); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); EXPECT_THAT(out.ByteCount(), Eq(10u)); - memcpy(buffer, input.c_str(), size); + memcpy(reinterpret_cast<char*>(buffer), input.c_str(), size); - ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); + ASSERT_TRUE(out.Next(&buffer, &size)); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); EXPECT_THAT(out.ByteCount(), Eq(20u)); - memcpy(buffer, input.c_str() + 10u, size); + memcpy(reinterpret_cast<char*>(buffer), input.c_str() + 10u, size); - ASSERT_TRUE(out.Next(reinterpret_cast<void**>(&buffer), &size)); + ASSERT_TRUE(out.Next(&buffer, &size)); ASSERT_THAT(size, Eq(10u)); ASSERT_THAT(buffer, NotNull()); EXPECT_THAT(out.ByteCount(), Eq(30u)); - buffer[0] = input[20u]; + reinterpret_cast<char*>(buffer)[0] = input[20u]; out.BackUp(size - 1); EXPECT_THAT(out.ByteCount(), Eq(21u)); |