diff options
248 files changed, 6124 insertions, 2775 deletions
diff --git a/Android.bp b/Android.bp index 487bf7a22e21..70b1fa0e793f 100644 --- a/Android.bp +++ b/Android.bp @@ -98,6 +98,7 @@ java_library { "core/java/android/app/backup/IRestoreObserver.aidl", "core/java/android/app/backup/IRestoreSession.aidl", "core/java/android/app/backup/ISelectBackupTransportCallback.aidl", + "core/java/android/app/slice/ISliceManager.aidl", "core/java/android/app/timezone/ICallback.aidl", "core/java/android/app/timezone/IRulesManager.aidl", "core/java/android/app/usage/ICacheQuotaService.aidl", diff --git a/Android.mk b/Android.mk index ce504a5abdd3..7ca8358c637a 100644 --- a/Android.mk +++ b/Android.mk @@ -46,6 +46,7 @@ aidl_files := \ frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \ frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \ frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \ + frameworks/base/telephony/java/android/telephony/data/DataCallResponse.aidl \ frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \ frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \ frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \ @@ -95,6 +96,7 @@ aidl_files := \ frameworks/base/core/java/android/app/admin/NetworkEvent.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/app/admin/PasswordMetrics.aidl \ + frameworks/base/core/java/android/app/slice/ISliceManager.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ frameworks/base/core/java/android/print/PageRange.aidl \ frameworks/base/core/java/android/print/PrintAttributes.aidl \ diff --git a/api/current.txt b/api/current.txt index f16ff1406e82..a30d560de424 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1505,6 +1505,7 @@ package android { field public static final deprecated int weekSeparatorLineColor = 16843590; // 0x1010346 field public static final int weightSum = 16843048; // 0x1010128 field public static final int widgetCategory = 16843716; // 0x10103c4 + field public static final int widgetFeatures = 16844153; // 0x1010579 field public static final int widgetLayout = 16843243; // 0x10101eb field public static final int width = 16843097; // 0x1010159 field public static final int windowActionBar = 16843469; // 0x10102cd @@ -4994,7 +4995,7 @@ package android.app { public class KeyguardManager { method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence); method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult); - method public boolean inKeyguardRestrictedInputMode(); + method public deprecated boolean inKeyguardRestrictedInputMode(); method public boolean isDeviceLocked(); method public boolean isDeviceSecure(); method public boolean isKeyguardLocked(); @@ -6322,6 +6323,7 @@ package android.app.admin { method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int); method public void enableSystemApp(android.content.ComponentName, java.lang.String); method public int enableSystemApp(android.content.ComponentName, android.content.Intent); + method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec); method public java.lang.String[] getAccountTypesWithManagementDisabled(); method public java.util.List<android.content.ComponentName> getActiveAdmins(); method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName); @@ -6370,6 +6372,7 @@ package android.app.admin { method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName); method public long getRequiredStrongAuthTimeout(android.content.ComponentName); method public boolean getScreenCaptureDisabled(android.content.ComponentName); + method public java.util.List<android.os.UserHandle> getSecondaryUsers(android.content.ComponentName); method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); @@ -6402,6 +6405,7 @@ package android.app.admin { method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String); method public void lockNow(); method public void lockNow(int); + method public boolean logoutUser(android.content.ComponentName); method public void reboot(android.content.ComponentName); method public void removeActiveAdmin(android.content.ComponentName); method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); @@ -6476,6 +6480,7 @@ package android.app.admin { method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle); method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean); method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap); + method public boolean stopUser(android.content.ComponentName, android.os.UserHandle); method public boolean switchUser(android.content.ComponentName, android.os.UserHandle); method public void uninstallAllUserCaCerts(android.content.ComponentName); method public void uninstallCaCert(android.content.ComponentName, byte[]); @@ -7348,6 +7353,8 @@ package android.appwidget { field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1 field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2 field public static final int WIDGET_CATEGORY_SEARCHBOX = 4; // 0x4 + field public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; // 0x2 + field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1 field public int autoAdvanceViewId; field public android.content.ComponentName configure; field public int icon; @@ -7363,6 +7370,7 @@ package android.appwidget { field public int resizeMode; field public int updatePeriodMillis; field public int widgetCategory; + field public int widgetFeatures; } } @@ -10077,6 +10085,7 @@ package android.content { public abstract interface ServiceConnection { method public default void onBindingDied(android.content.ComponentName); + method public default void onNullBinding(android.content.ComponentName); method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder); method public abstract void onServiceDisconnected(android.content.ComponentName); } @@ -11252,6 +11261,8 @@ package android.content.pm { package android.content.pm.crossprofile { public class CrossProfileApps { + method public android.graphics.drawable.Drawable getProfileSwitchingIcon(android.os.UserHandle); + method public java.lang.CharSequence getProfileSwitchingLabel(android.os.UserHandle); method public java.util.List<android.os.UserHandle> getTargetUserProfiles(); method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); } @@ -37139,6 +37150,11 @@ package android.sax { package android.security { + public final class AttestedKeyPair { + method public java.util.List<java.security.cert.Certificate> getAttestationRecord(); + method public java.security.KeyPair getKeyPair(); + } + public final class KeyChain { ctor public KeyChain(); method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String); @@ -39661,12 +39677,15 @@ package android.telecom { method public final void addConference(android.telecom.Conference); method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection); method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); + method public final void connectionServiceFocusReleased(); method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final java.util.Collection<android.telecom.Conference> getAllConferences(); method public final java.util.Collection<android.telecom.Connection> getAllConnections(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); + method public void onConnectionServiceFocusGained(); + method public void onConnectionServiceFocusLost(); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); @@ -47970,7 +47989,6 @@ package android.view.accessibility { method public void interrupt(); method public static boolean isAccessibilityButtonSupported(); method public boolean isEnabled(); - method public boolean isObservedEventType(int); method public boolean isTouchExplorationEnabled(); method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer); method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener); diff --git a/api/system-current.txt b/api/system-current.txt index b964d8a02b45..33fa246a9f51 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -783,11 +783,12 @@ package android.content.pm { public final class InstantAppResolveInfo implements android.os.Parcelable { ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int); - ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long); + ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long, android.os.Bundle); ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>); method public int describeContents(); method public byte[] getDigestBytes(); method public int getDigestPrefix(); + method public android.os.Bundle getExtras(); method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters(); method public long getLongVersionCode(); method public java.lang.String getPackageName(); @@ -4176,6 +4177,25 @@ package android.telephony { package android.telephony.data { + public final class DataCallResponse implements android.os.Parcelable { + ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.telephony.data.InterfaceAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int); + ctor public DataCallResponse(android.os.Parcel); + method public int describeContents(); + method public int getActive(); + method public java.util.List<android.telephony.data.InterfaceAddress> getAddresses(); + method public int getCallId(); + method public java.util.List<java.net.InetAddress> getDnses(); + method public java.util.List<java.net.InetAddress> getGateways(); + method public java.lang.String getIfname(); + method public int getMtu(); + method public java.util.List<java.lang.String> getPcscfs(); + method public int getStatus(); + method public int getSuggestedRetryTime(); + method public java.lang.String getType(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; + } + public final class DataProfile implements android.os.Parcelable { ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean); ctor public DataProfile(android.os.Parcel); @@ -4205,6 +4225,17 @@ package android.telephony.data { field public static final int TYPE_COMMON = 0; // 0x0 } + public final class InterfaceAddress implements android.os.Parcelable { + ctor public InterfaceAddress(java.net.InetAddress, int); + ctor public InterfaceAddress(java.lang.String, int) throws java.net.UnknownHostException; + ctor public InterfaceAddress(android.os.Parcel); + method public int describeContents(); + method public java.net.InetAddress getAddress(); + method public int getNetworkPrefixLength(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.data.InterfaceAddress> CREATOR; + } + } package android.telephony.ims { diff --git a/api/test-current.txt b/api/test-current.txt index 7e0731a6548e..3c3521feff95 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -425,7 +425,7 @@ package android.provider { public static final class Settings.Secure extends android.provider.Settings.NameValueTable { field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled"; - field public static final java.lang.String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection"; + field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service"; field public static final java.lang.String DISABLED_PRINT_SERVICES = "disabled_print_services"; field public static final deprecated java.lang.String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages"; @@ -457,8 +457,31 @@ package android.service.autofill { method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception; } + public final class EditDistanceScorer extends android.service.autofill.InternalScorer implements android.os.Parcelable android.service.autofill.Scorer { + method public int describeContents(); + method public static android.service.autofill.EditDistanceScorer getInstance(); + method public float getScore(android.view.autofill.AutofillValue, java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.EditDistanceScorer> CREATOR; + } + + public final class FieldClassification implements android.os.Parcelable { + method public int describeContents(); + method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification> CREATOR; + } + + public static final class FieldClassification.Match implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getRemoteId(); + method public float getScore(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.autofill.FieldClassification.Match> CREATOR; + } + public static final class FillEventHistory.Event { - method public java.util.Map<java.lang.String, java.lang.Integer> getFieldsClassification(); + method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification(); } public static final class FillResponse.Builder { @@ -473,6 +496,11 @@ package android.service.autofill { ctor public InternalSanitizer(); } + public abstract class InternalScorer implements android.os.Parcelable android.service.autofill.Scorer { + ctor public InternalScorer(); + method public abstract float getScore(android.view.autofill.AutofillValue, java.lang.String); + } + public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation { ctor public InternalTransformation(); } @@ -490,6 +518,9 @@ package android.service.autofill { method public boolean isValid(android.service.autofill.ValueFinder); } + public abstract interface Scorer { + } + public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer { method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue); } @@ -505,7 +536,7 @@ package android.service.autofill { } public static final class UserData.Builder { - ctor public UserData.Builder(java.lang.String, java.lang.String); + ctor public UserData.Builder(android.service.autofill.Scorer, java.lang.String, java.lang.String); method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String); method public android.service.autofill.UserData build(); } @@ -941,15 +972,6 @@ package android.view { package android.view.accessibility { - public final class AccessibilityManager { - method public void addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, android.os.Handler); - method public void removeAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener); - } - - public static abstract interface AccessibilityManager.AccessibilityServicesStateChangeListener { - method public abstract void onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager); - } - public class AccessibilityNodeInfo implements android.os.Parcelable { method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger); } @@ -968,6 +990,7 @@ package android.view.autofill { public final class AutofillManager { method public android.service.autofill.UserData getUserData(); + method public boolean isFieldClassificationEnabled(); method public void setUserData(android.service.autofill.UserData); } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 968d08f90992..c81fc1dec7ab 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -103,7 +103,11 @@ message Atom { * resulted in a particular bit of work being done. */ message WorkSource { - // TODO + // The uid for a given element in the attribution chain. + repeated int32 uid = 1; + // The (optional) string tag for an element in the attribution chain. If the + // element has no tag, it is encoded as an empty string. + repeated string tag = 2; } /* @@ -413,8 +417,10 @@ message WakelockStateChanged { optional string tag = 3; enum State { - OFF = 0; - ON = 1; + RELEASE = 0; + ACQUIRE = 1; + CHANGE_RELEASE = 2; + CHANGE_ACQUIRE = 3; } optional State state = 4; } @@ -1066,4 +1072,4 @@ message ModemActivityInfoPulled { optional uint64 controller_rx_time_ms = 9; // product of current(mA), voltage(V) and time(ms) optional uint64 energy_used = 10; -} +}
\ No newline at end of file diff --git a/cmds/statsd/src/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto index 58e225a317f0..18b21449ebc6 100644 --- a/cmds/statsd/src/atoms_copy.proto +++ b/cmds/statsd/src/atoms_copy.proto @@ -99,7 +99,11 @@ message Atom { * resulted in a particular bit of work being done. */ message WorkSource { - // TODO + // The uid for a given element in the attribution chain. + repeated int32 uid = 1; + // The (optional) string tag for an element in the attribution chain. If the + // element has no tag, it is encoded as an empty string. + repeated string tag = 2; } /* @@ -404,8 +408,10 @@ message WakelockStateChanged { optional string tag = 3; enum State { - OFF = 0; - ON = 1; + RELEASE = 0; + ACQUIRE = 1; + CHANGE_RELEASE = 2; + CHANGE_ACQUIRE = 3; } optional State state = 4; } @@ -907,4 +913,4 @@ message CpuTimePerUidFreqPulled { optional uint64 uid = 1; optional uint64 freq_idx = 2; optional uint64 time_ms = 3; -} +}
\ No newline at end of file diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h index 1a01afa7fbdc..30a368412c8e 100644 --- a/cmds/statsd/src/condition/ConditionWizard.h +++ b/cmds/statsd/src/condition/ConditionWizard.h @@ -24,7 +24,7 @@ namespace android { namespace os { namespace statsd { -// Held by MetricProducer, to query a condition state with input defined in EventConditionLink. +// Held by MetricProducer, to query a condition state with input defined in MetricConditionLink. class ConditionWizard : public virtual android::RefBase { public: ConditionWizard(){}; // for testing diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp index 669a4b77f3b4..ff0e3bc0d21a 100644 --- a/cmds/statsd/src/condition/condition_util.cpp +++ b/cmds/statsd/src/condition/condition_util.cpp @@ -94,17 +94,17 @@ ConditionState evaluateCombinationCondition(const std::vector<int>& children, } HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event, - const EventConditionLink& link) { + const MetricConditionLink& link) { vector<KeyMatcher> eventKey; - eventKey.reserve(link.key_in_main().size()); + eventKey.reserve(link.key_in_what().size()); - for (const auto& key : link.key_in_main()) { + for (const auto& key : link.key_in_what()) { eventKey.push_back(key); } vector<KeyValuePair> dimensionKey = getDimensionKey(event, eventKey); - for (int i = 0; i < link.key_in_main_size(); i++) { + for (int i = 0; i < link.key_in_what_size(); i++) { auto& kv = dimensionKey[i]; kv.set_key(link.key_in_condition(i).key()); } diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h index 4167bf922b19..934c2076ddfa 100644 --- a/cmds/statsd/src/condition/condition_util.h +++ b/cmds/statsd/src/condition/condition_util.h @@ -37,7 +37,7 @@ ConditionState evaluateCombinationCondition(const std::vector<int>& children, const std::vector<ConditionState>& conditionCache); HashableDimensionKey getDimensionKeyForCondition(const LogEvent& event, - const EventConditionLink& link); + const MetricConditionLink& link); } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index 6a76c5573b90..540199d59910 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -214,7 +214,8 @@ StatsdConfig build_fake_config() { int UID_PROCESS_STATE_UID_KEY = 1; int KERNEL_WAKELOCK_TAG_ID = 1004; - int KERNEL_WAKELOCK_NAME_KEY = 4; + int KERNEL_WAKELOCK_COUNT_KEY = 2; + int KERNEL_WAKELOCK_NAME_KEY = 1; int DEVICE_TEMPERATURE_TAG_ID = 33; int DEVICE_TEMPERATURE_KEY = 1; @@ -272,9 +273,9 @@ StatsdConfig build_fake_config() { keyMatcher = metric->add_dimension(); keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID); metric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON"); - EventConditionLink* link = metric->add_links(); + MetricConditionLink* link = metric->add_links(); link->set_condition("APP_IS_BACKGROUND"); - link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID); + link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID); link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID); // Duration of an app holding any wl, while screen on and app in background, slice by uid @@ -288,7 +289,7 @@ StatsdConfig build_fake_config() { durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON"); link = durationMetric->add_links(); link->set_condition("APP_IS_BACKGROUND"); - link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID); + link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID); link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID); // max Duration of an app holding any wl, while screen on and app in background, slice by uid @@ -302,7 +303,7 @@ StatsdConfig build_fake_config() { durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON"); link = durationMetric->add_links(); link->set_condition("APP_IS_BACKGROUND"); - link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID); + link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID); link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID); // Duration of an app holding any wl, while screen on and app in background @@ -314,7 +315,7 @@ StatsdConfig build_fake_config() { durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON"); link = durationMetric->add_links(); link->set_condition("APP_IS_BACKGROUND"); - link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID); + link->add_key_in_what()->set_key(WAKE_LOCK_UID_KEY_ID); link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID); // Duration of screen on time. @@ -338,7 +339,7 @@ StatsdConfig build_fake_config() { ValueMetric* valueMetric = config.add_value_metric(); valueMetric->set_name("METRIC_6"); valueMetric->set_what("KERNEL_WAKELOCK"); - valueMetric->set_value_field(1); + valueMetric->set_value_field(KERNEL_WAKELOCK_COUNT_KEY); valueMetric->set_condition("SCREEN_IS_ON"); keyMatcher = valueMetric->add_dimension(); keyMatcher->set_key(KERNEL_WAKELOCK_NAME_KEY); diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp index e1c02d74d601..ffe1be9ca2e0 100644 --- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp +++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp @@ -49,15 +49,15 @@ bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEve return false; } data->clear(); - long timestamp = time(nullptr); + int timestamp = time(nullptr); for (const StatsLogEventWrapper& it : returned_value) { log_msg tmp; tmp.entry_v1.len = it.bytes.size(); // Manually set the header size to 28 bytes to match the pushed log events. tmp.entry.hdr_size = kLogMsgHeaderSize; + tmp.entry_v1.sec = timestamp; // And set the received bytes starting after the 28 bytes reserved for header. std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize); - tmp.entry_v1.sec = timestamp; data->push_back(make_shared<LogEvent>(tmp)); } ALOGD("StatsCompanionServicePuller::pull succeeded for %d", tagId); diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 534d54eb0bea..9e88e5d0d8e3 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -117,6 +117,9 @@ bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& event allMatched = false; break; } + } else { + allMatched = false; + break; } } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt || matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt || @@ -153,6 +156,9 @@ bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& event break; } } + } else { + allMatched = false; + break; } } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) { // Boolean fields @@ -163,6 +169,9 @@ bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& event allMatched = false; break; } + } else { + allMatched = false; + break; } } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat || matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) { @@ -181,6 +190,9 @@ bool matchesSimple(const SimpleAtomMatcher& simpleMatcher, const LogEvent& event break; } } + } else { + allMatched = false; + break; } } else { // If value matcher is not present, assume that we match. diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 50cc8d407fb9..1f6bd58b5492 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -203,7 +203,7 @@ void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet, return; } for (const auto& data : allData) { - onMatchedLogEvent(0, *data, false /*scheduledPull*/); + onMatchedLogEventLocked(0, *data, false /*scheduledPull*/); } flushIfNeededLocked(eventTime); } @@ -227,7 +227,7 @@ void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven std::lock_guard<std::mutex> lock(mMutex); for (const auto& data : allData) { - onMatchedLogEvent(0, *data, true /*scheduledPull*/); + onMatchedLogEventLocked(0, *data, true /*scheduledPull*/); } } diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 819df7705a75..e7e84ab1dcc8 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -137,7 +137,7 @@ protected: // that StatsLogReport wants. std::unordered_map<HashableDimensionKey, std::vector<KeyValuePair>> mDimensionKeyMap; - std::vector<EventConditionLink> mConditionLinks; + std::vector<MetricConditionLink> mConditionLinks; std::vector<sp<AnomalyTracker>> mAnomalyTrackers; @@ -149,7 +149,7 @@ protected: * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have * dimensions, it will be DEFAULT_DIMENSION_KEY * [conditionKey]: the keys of conditions which should be used to query the condition for this - * target event (from EventConditionLink). This is passed to individual metrics + * target event (from MetricConditionLink). This is passed to individual metrics * because DurationMetric needs it to be cached. * [condition]: whether condition is met. If condition is sliced, this is the result coming from * query with ConditionWizard; If condition is not sliced, this is the diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 1fc4d425a6bd..943becb6fb3c 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -64,7 +64,7 @@ bool handleMetricWithLogTrackers(const string what, const int metricIndex, bool handleMetricWithConditions( const string condition, const int metricIndex, const unordered_map<string, int>& conditionTrackerMap, - const ::google::protobuf::RepeatedPtrField<::android::os::statsd::EventConditionLink>& + const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>& links, vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex, unordered_map<int, std::vector<int>>& conditionToMetricMap) { @@ -232,7 +232,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, } } else { if (metric.links_size() > 0) { - ALOGW("metrics has a EventConditionLink but doesn't have a condition"); + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); return false; } } @@ -303,7 +303,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, } } else { if (metric.links_size() > 0) { - ALOGW("metrics has a EventConditionLink but doesn't have a condition"); + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); return false; } } @@ -340,7 +340,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, } } else { if (metric.links_size() > 0) { - ALOGW("metrics has a EventConditionLink but doesn't have a condition"); + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); return false; } } @@ -390,7 +390,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, } } else { if (metric.links_size() > 0) { - ALOGW("metrics has a EventConditionLink but doesn't have a condition"); + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); return false; } } @@ -439,7 +439,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, } } else { if (metric.links_size() > 0) { - ALOGW("metrics has a EventConditionLink but doesn't have a condition"); + ALOGW("metrics has a MetricConditionLink but doesn't have a condition"); return false; } } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 751d8dff02f8..8e9c8e3616ab 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -62,7 +62,7 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config, std::unordered_map<std::string, int>& conditionTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, std::unordered_map<int, std::vector<int>>& trackerToConditionMap, - std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks); + std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks); // Initialize MetricProducers. // input: @@ -79,7 +79,7 @@ bool initMetrics( const ConfigKey& key, const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap, const std::unordered_map<std::string, int>& conditionTrackerMap, - const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks, + const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks, const vector<sp<LogMatchingTracker>>& allAtomMatchers, vector<sp<ConditionTracker>>& allConditionTrackers, std::vector<sp<MetricProducer>>& allMetricProducers, diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index ca63b033a625..c9654af13137 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -112,10 +112,10 @@ message Bucket { optional int64 bucket_size_millis = 1; } -message EventConditionLink { +message MetricConditionLink { optional string condition = 1; - repeated KeyMatcher key_in_main = 2; + repeated KeyMatcher key_in_what = 2; repeated KeyMatcher key_in_condition = 3; } @@ -127,7 +127,7 @@ message EventMetric { optional string condition = 3; - repeated EventConditionLink links = 4; + repeated MetricConditionLink links = 4; } message CountMetric { @@ -141,7 +141,7 @@ message CountMetric { optional Bucket bucket = 5; - repeated EventConditionLink links = 6; + repeated MetricConditionLink links = 6; } message DurationMetric { @@ -151,7 +151,7 @@ message DurationMetric { optional string condition = 3; - repeated EventConditionLink links = 4; + repeated MetricConditionLink links = 4; enum AggregationType { SUM = 1; @@ -178,7 +178,7 @@ message GaugeMetric { optional Bucket bucket = 6; - repeated EventConditionLink links = 7; + repeated MetricConditionLink links = 7; } message ValueMetric { @@ -194,7 +194,7 @@ message ValueMetric { optional Bucket bucket = 6; - repeated EventConditionLink links = 7; + repeated MetricConditionLink links = 7; enum AggregationType { SUM = 1; } optional AggregationType aggregation_type = 8 [default = SUM]; diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index dc42943e8233..9b94099625a5 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -141,9 +141,9 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { metric.set_name("1"); metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000); metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"); - EventConditionLink* link = metric.add_links(); + MetricConditionLink* link = metric.add_links(); link->set_condition("APP_IN_BACKGROUND_PER_UID"); - link->add_key_in_main()->set_key(1); + link->add_key_in_what()->set_key(1); link->add_key_in_condition()->set_key(2); LogEvent event1(1, bucketStartTimeNs + 1); diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index 724ad59eeab6..f3302fd5b8e9 100644 --- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp @@ -91,9 +91,9 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { EventMetric metric; metric.set_name("1"); metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"); - EventConditionLink* link = metric.add_links(); + MetricConditionLink* link = metric.add_links(); link->set_condition("APP_IN_BACKGROUND_PER_UID"); - link->add_key_in_main()->set_key(1); + link->add_key_in_what()->set_key(1); link->add_key_in_condition()->set_key(2); LogEvent event1(1, bucketStartTimeNs + 1); diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java index 95a592b58211..0d890fbb6e56 100644 --- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java +++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java @@ -23,7 +23,7 @@ import com.android.internal.os.StatsdConfigProto.Bucket; import com.android.internal.os.StatsdConfigProto.Predicate; import com.android.internal.os.StatsdConfigProto.CountMetric; import com.android.internal.os.StatsdConfigProto.DurationMetric; -import com.android.internal.os.StatsdConfigProto.EventConditionLink; +import com.android.internal.os.StatsdConfigProto.MetricConditionLink; import com.android.internal.os.StatsdConfigProto.EventMetric; import com.android.internal.os.StatsdConfigProto.GaugeMetric; import com.android.internal.os.StatsdConfigProto.ValueMetric; @@ -129,13 +129,13 @@ public class ConfigFactory { } /** - * Creates {@link EventConditionLink}s that are identical to the one passed to this method, + * Creates {@link MetricConditionLink}s that are identical to the one passed to this method, * except that the names are appended with the provided suffix. */ - private List<EventConditionLink> getLinks( - List<EventConditionLink> links, int suffix) { - List<EventConditionLink> newLinks = new ArrayList(); - for (EventConditionLink link : links) { + private List<MetricConditionLink> getLinks( + List<MetricConditionLink> links, int suffix) { + List<MetricConditionLink> newLinks = new ArrayList(); + for (MetricConditionLink link : links) { newLinks.add(link.toBuilder() .setCondition(link.getCondition() + suffix) .build()); @@ -155,7 +155,7 @@ public class ConfigFactory { metric.setCondition(template.getCondition() + suffix); } if (template.getLinksCount() > 0) { - List<EventConditionLink> links = getLinks(template.getLinksList(), suffix); + List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); metric.clearLinks(); metric.addAllLinks(links); } @@ -181,7 +181,7 @@ public class ConfigFactory { metric.setCondition(template.getCondition() + suffix); } if (template.getLinksCount() > 0) { - List<EventConditionLink> links = getLinks(template.getLinksList(), suffix); + List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); metric.clearLinks(); metric.addAllLinks(links); } @@ -202,7 +202,7 @@ public class ConfigFactory { metric.setCondition(template.getCondition() + suffix); } if (template.getLinksCount() > 0) { - List<EventConditionLink> links = getLinks(template.getLinksList(), suffix); + List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); metric.clearLinks(); metric.addAllLinks(links); } @@ -223,7 +223,7 @@ public class ConfigFactory { metric.setCondition(template.getCondition() + suffix); } if (template.getLinksCount() > 0) { - List<EventConditionLink> links = getLinks(template.getLinksList(), suffix); + List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); metric.clearLinks(); metric.addAllLinks(links); } @@ -244,7 +244,7 @@ public class ConfigFactory { metric.setCondition(template.getCondition() + suffix); } if (template.getLinksCount() > 0) { - List<EventConditionLink> links = getLinks(template.getLinksList(), suffix); + List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix); metric.clearLinks(); metric.addAllLinks(links); } diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk index e6cbdb4ec49b..008bb935cb71 100644 --- a/cmds/uiautomator/instrumentation/Android.mk +++ b/cmds/uiautomator/instrumentation/Android.mk @@ -22,7 +22,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \ $(call all-java-files-under, ../library/core-src) LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit +LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_MODULE := uiautomator-instrumentation # TODO: change this to 18 when it's available LOCAL_SDK_VERSION := current diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk index 4bf856f8cbfa..22cffe60b2a8 100644 --- a/cmds/uiautomator/library/Android.mk +++ b/cmds/uiautomator/library/Android.mk @@ -28,8 +28,8 @@ uiautomator_internal_removed_api_file := \ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(uiautomator.core_src_files) LOCAL_MODULE := uiautomator.core -LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base +LOCAL_STATIC_JAVA_LIBRARIES := junit include $(BUILD_STATIC_JAVA_LIBRARY) ############################################### diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index e0d60cd059d0..06a9b0676d08 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -16,8 +16,6 @@ package android.accessibilityservice; -import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; - import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -49,6 +47,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; + /** * This class describes an {@link AccessibilityService}. The system notifies an * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s @@ -554,7 +554,7 @@ public class AccessibilityServiceInfo implements Parcelable { } /** - * Updates the properties that an AccessibilityService can change dynamically. + * Updates the properties that an AccessibilitySerivice can change dynamically. * * @param other The info from which to update the properties. * diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 1fe29004e162..d0f84c8ee0bb 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -382,6 +382,8 @@ public class KeyguardManager { } /** + * @deprecated Use {@link #isKeyguardLocked()} instead. + * * If keyguard screen is showing or in restricted key input mode (i.e. in * keyguard password emergency screen). When in such mode, certain keys, * such as the Home key and the right soft keys, don't work. @@ -389,11 +391,7 @@ public class KeyguardManager { * @return true if in keyguard restricted input mode. */ public boolean inKeyguardRestrictedInputMode() { - try { - return mWM.inKeyguardRestrictedInputMode(); - } catch (RemoteException ex) { - return false; - } + return isKeyguardLocked(); } /** diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index de6230cf825a..ebd101494588 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -1646,9 +1646,12 @@ public final class LoadedApk { if (dead) { mConnection.onBindingDied(name); } - // If there is a new service, it is now connected. + // If there is a new viable service, it is now connected. if (service != null) { mConnection.onServiceConnected(name, service); + } else { + // The binding machinery worked, but the remote returned null from onBind(). + mConnection.onNullBinding(name); } } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index e48946f2c3e4..f831ae220703 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -22,6 +22,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.app.job.IJobScheduler; import android.app.job.JobScheduler; +import android.app.slice.SliceManager; import android.app.timezone.RulesManager; import android.app.trust.TrustManager; import android.app.usage.IStorageStatsManager; @@ -944,6 +945,16 @@ final class SystemServiceRegistry { ICrossProfileApps.Stub.asInterface(b)); } }); + + registerService(Context.SLICE_SERVICE, SliceManager.class, + new CachedServiceFetcher<SliceManager>() { + @Override + public SliceManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + return new SliceManager(ctx.getOuterContext(), + ctx.mMainThread.getHandler()); + } + }); } /** diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index acdad1c44c90..562b981941a7 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -57,7 +57,12 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract.Directory; +import android.security.AttestedKeyPair; import android.security.Credentials; +import android.security.KeyChain; +import android.security.KeyChainException; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.ParcelableKeyGenParameterSpec; import android.service.restrictions.RestrictionsReceiver; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -75,6 +80,7 @@ import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.Proxy; import java.security.KeyFactory; +import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -3943,6 +3949,50 @@ public class DevicePolicyManager { } /** + * Called by a device or profile owner, or delegated certificate installer, to generate a + * new private/public key pair. If the device supports key generation via secure hardware, + * this method is useful for creating a key in KeyChain that never left the secure hardware. + * + * Access to the key is controlled the same way as in {@link #installKeyPair}. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}. + * @param keySpec Specification of the key to generate, see + * {@link java.security.KeyPairGenerator}. + * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise. + * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile + * owner. + * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the + * algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec} + * or {@code ECGenParameterSpec}. + */ + public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin, + @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) { + throwIfParentInstance("generateKeyPair"); + try { + final ParcelableKeyGenParameterSpec parcelableSpec = + new ParcelableKeyGenParameterSpec(keySpec); + final boolean success = mService.generateKeyPair( + admin, mContext.getPackageName(), algorithm, parcelableSpec); + if (!success) { + Log.e(TAG, "Error generating key via DevicePolicyManagerService."); + return null; + } + + final KeyPair keyPair = KeyChain.getKeyPair(mContext, keySpec.getKeystoreAlias()); + return new AttestedKeyPair(keyPair, null); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (KeyChainException e) { + Log.w(TAG, "Failed to generate key", e); + } catch (InterruptedException e) { + Log.w(TAG, "Interrupted while generating key", e); + Thread.currentThread().interrupt(); + } + return null; + } + + /** * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. */ @@ -6219,7 +6269,7 @@ public class DevicePolicyManager { * @return {@code true} if the user was removed, {@code false} otherwise. * @throws SecurityException if {@code admin} is not a device owner. */ - public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) { + public boolean removeUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) { throwIfParentInstance("removeUser"); try { return mService.removeUser(admin, userHandle); @@ -6230,6 +6280,7 @@ public class DevicePolicyManager { /** * Called by a device owner to switch the specified user to the foreground. + * <p> This cannot be used to switch to a managed profile. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param userHandle the user to switch to; null will switch to primary. @@ -6247,6 +6298,65 @@ public class DevicePolicyManager { } /** + * Called by a device owner to stop the specified secondary user. + * <p> This cannot be used to stop the primary user or a managed profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userHandle the user to be stopped. + * @return {@code true} if the user can be stopped, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not a device owner. + */ + public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) { + throwIfParentInstance("stopUser"); + try { + return mService.stopUser(admin, userHandle); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by a profile owner that is affiliated with the device owner to stop the calling user + * and switch back to primary. + * <p> This has no effect when called on a managed profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return {@code true} if the exit was successful, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device + * owner. + */ + public boolean logoutUser(@NonNull ComponentName admin) { + throwIfParentInstance("logoutUser"); + try { + return mService.logoutUser(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by a device owner to list all secondary users on the device, excluding managed + * profiles. + * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser} + * and {@link #stopUser}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return list of other {@link UserHandle}s on the device. + * @throws SecurityException if {@code admin} is not a device owner. + * @see #switchUser + * @see #removeUser + * @see #stopUser + */ + public List<UserHandle> getSecondaryUsers(@NonNull ComponentName admin) { + throwIfParentInstance("getSecondaryUsers"); + try { + return mService.getSecondaryUsers(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Retrieves the application restrictions for a given target application running in the calling * user. * <p> diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 4925f341fd94..c525df725d47 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -36,6 +36,7 @@ import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteCallback; import android.os.UserHandle; +import android.security.keystore.ParcelableKeyGenParameterSpec; import java.util.List; @@ -165,6 +166,7 @@ interface IDevicePolicyManager { in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess, boolean isUserSelectable); boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias); + boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm, in ParcelableKeyGenParameterSpec keySpec); void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback); void setDelegatedScopes(in ComponentName who, in String delegatePackage, in List<String> scopes); @@ -215,6 +217,9 @@ interface IDevicePolicyManager { UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags); boolean removeUser(in ComponentName who, in UserHandle userHandle); boolean switchUser(in ComponentName who, in UserHandle userHandle); + boolean stopUser(in ComponentName who, in UserHandle userHandle); + boolean logoutUser(in ComponentName who); + List<UserHandle> getSecondaryUsers(in ComponentName who); void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName); int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent); diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl new file mode 100644 index 000000000000..6e52f385bcf7 --- /dev/null +++ b/core/java/android/app/slice/ISliceManager.aidl @@ -0,0 +1,21 @@ +/** + * 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.app.slice; + +/** @hide */ +interface ISliceManager { +} diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java new file mode 100644 index 000000000000..e99f67632712 --- /dev/null +++ b/core/java/android/app/slice/SliceManager.java @@ -0,0 +1,39 @@ +/* + * 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.app.slice; + +import android.annotation.SystemService; +import android.content.Context; +import android.os.Handler; +import android.os.ServiceManager; +import android.os.ServiceManager.ServiceNotFoundException; + +/** + * @hide + */ +@SystemService(Context.SLICE_SERVICE) +public class SliceManager { + + private final ISliceManager mService; + private final Context mContext; + + public SliceManager(Context context, Handler handler) throws ServiceNotFoundException { + mContext = context; + mService = ISliceManager.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.SLICE_SERVICE)); + } +} diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index fd1b0e0274b1..75ce4fbb60c7 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -17,15 +17,17 @@ package android.appwidget; import android.annotation.NonNull; +import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.ResourceId; import android.content.res.Resources; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.content.ComponentName; import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -69,6 +71,23 @@ public class AppWidgetProviderInfo implements Parcelable { public static final int WIDGET_CATEGORY_SEARCHBOX = 4; /** + * The widget can be reconfigured anytime after it is bound by starting the + * {@link #configure} activity. + * + * @see #widgetFeatures + */ + public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; + + /** + * The widget is added directly by the app, and the host may hide this widget when providing + * the user with the list of available widgets to choose from. + * + * @see AppWidgetManager#requestPinAppWidget(ComponentName, Bundle, PendingIntent) + * @see #widgetFeatures + */ + public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; + + /** * Identity of this AppWidget component. This component should be a {@link * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents * {@link android.appwidget as described in the AppWidget package documentation}. @@ -209,6 +228,15 @@ public class AppWidgetProviderInfo implements Parcelable { */ public int widgetCategory; + /** + * Flags indicating various features supported by the widget. These are hints to the widget + * host, and do not actually change the behavior of the widget. + * + * @see #WIDGET_FEATURE_RECONFIGURABLE + * @see #WIDGET_FEATURE_HIDE_FROM_PICKER + */ + public int widgetFeatures; + /** @hide */ public ActivityInfo providerInfo; @@ -221,9 +249,7 @@ public class AppWidgetProviderInfo implements Parcelable { */ @SuppressWarnings("deprecation") public AppWidgetProviderInfo(Parcel in) { - if (0 != in.readInt()) { - this.provider = new ComponentName(in); - } + this.provider = in.readTypedObject(ComponentName.CREATOR); this.minWidth = in.readInt(); this.minHeight = in.readInt(); this.minResizeWidth = in.readInt(); @@ -231,16 +257,15 @@ public class AppWidgetProviderInfo implements Parcelable { this.updatePeriodMillis = in.readInt(); this.initialLayout = in.readInt(); this.initialKeyguardLayout = in.readInt(); - if (0 != in.readInt()) { - this.configure = new ComponentName(in); - } + this.configure = in.readTypedObject(ComponentName.CREATOR); this.label = in.readString(); this.icon = in.readInt(); this.previewImage = in.readInt(); this.autoAdvanceViewId = in.readInt(); this.resizeMode = in.readInt(); this.widgetCategory = in.readInt(); - this.providerInfo = in.readParcelable(null); + this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR); + this.widgetFeatures = in.readInt(); } /** @@ -308,13 +333,8 @@ public class AppWidgetProviderInfo implements Parcelable { @Override @SuppressWarnings("deprecation") - public void writeToParcel(android.os.Parcel out, int flags) { - if (this.provider != null) { - out.writeInt(1); - this.provider.writeToParcel(out, flags); - } else { - out.writeInt(0); - } + public void writeToParcel(Parcel out, int flags) { + out.writeTypedObject(this.provider, flags); out.writeInt(this.minWidth); out.writeInt(this.minHeight); out.writeInt(this.minResizeWidth); @@ -322,19 +342,15 @@ public class AppWidgetProviderInfo implements Parcelable { out.writeInt(this.updatePeriodMillis); out.writeInt(this.initialLayout); out.writeInt(this.initialKeyguardLayout); - if (this.configure != null) { - out.writeInt(1); - this.configure.writeToParcel(out, flags); - } else { - out.writeInt(0); - } + out.writeTypedObject(this.configure, flags); out.writeString(this.label); out.writeInt(this.icon); out.writeInt(this.previewImage); out.writeInt(this.autoAdvanceViewId); out.writeInt(this.resizeMode); out.writeInt(this.widgetCategory); - out.writeParcelable(this.providerInfo, flags); + out.writeTypedObject(this.providerInfo, flags); + out.writeInt(this.widgetFeatures); } @Override @@ -357,6 +373,7 @@ public class AppWidgetProviderInfo implements Parcelable { that.resizeMode = this.resizeMode; that.widgetCategory = this.widgetCategory; that.providerInfo = this.providerInfo; + that.widgetFeatures = this.widgetFeatures; return that; } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 578a5b8b93e1..c7be0f36ecef 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009-2016 The Android Open Source Project - * Copyright (C) 2015 Samsung LSI + * Copyright 2009-2016 The Android Open Source Project + * Copyright 2015 Samsung LSI * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -132,9 +132,8 @@ public final class BluetoothAdapter { * respectively. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_STATE_CHANGED = - "android.bluetooth.adapter.action.STATE_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} @@ -144,8 +143,7 @@ public final class BluetoothAdapter { * {@link #STATE_ON}, * {@link #STATE_TURNING_OFF}, */ - public static final String EXTRA_STATE = - "android.bluetooth.adapter.extra.STATE"; + public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} * intents to request the previous power state. Possible values are: @@ -158,11 +156,17 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.extra.PREVIOUS_STATE"; /** @hide */ - @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON, - STATE_BLE_ON, STATE_BLE_TURNING_OFF}) + @IntDef({ + STATE_OFF, + STATE_TURNING_ON, + STATE_ON, + STATE_TURNING_OFF, + STATE_BLE_TURNING_ON, + STATE_BLE_ON, + STATE_BLE_TURNING_OFF + }) @Retention(RetentionPolicy.SOURCE) - public @interface AdapterState { - } + public @interface AdapterState {} /** * Indicates the local Bluetooth adapter is off. @@ -254,9 +258,8 @@ public final class BluetoothAdapter { * application can be notified when the device has ended discoverability. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_DISCOVERABLE = - "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; /** * Used as an optional int extra field in {@link @@ -282,9 +285,8 @@ public final class BluetoothAdapter { * for global notification whenever Bluetooth is turned on or off. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_ENABLE = - "android.bluetooth.adapter.action.REQUEST_ENABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; /** * Activity Action: Show a system activity that allows the user to turn off @@ -305,9 +307,8 @@ public final class BluetoothAdapter { * * @hide */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_DISABLE = - "android.bluetooth.adapter.action.REQUEST_DISABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; /** * Activity Action: Show a system activity that allows user to enable BLE scans even when @@ -334,9 +335,8 @@ public final class BluetoothAdapter { * respectively. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_SCAN_MODE_CHANGED = - "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} @@ -359,8 +359,7 @@ public final class BluetoothAdapter { /** @hide */ @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) @Retention(RetentionPolicy.SOURCE) - public @interface ScanMode { - } + public @interface ScanMode {} /** * Indicates that both inquiry scan and page scan are disabled on the local @@ -396,17 +395,15 @@ public final class BluetoothAdapter { * discovery. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DISCOVERY_STARTED = - "android.bluetooth.adapter.action.DISCOVERY_STARTED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; /** * Broadcast Action: The local Bluetooth adapter has finished the device * discovery process. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DISCOVERY_FINISHED = - "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; /** * Broadcast Action: The local Bluetooth adapter has changed its friendly @@ -416,9 +413,8 @@ public final class BluetoothAdapter { * the name. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LOCAL_NAME_CHANGED = - "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; /** * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} * intents to request the local Bluetooth name. @@ -451,8 +447,8 @@ public final class BluetoothAdapter { * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; /** @@ -476,8 +472,7 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi - public static final String ACTION_BLE_STATE_CHANGED = + @SystemApi public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; /** @@ -574,8 +569,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; - private final ReentrantReadWriteLock mServiceLock = - new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); private final Object mLock = new Object(); private final Map<LeScanCallback, ScanCallback> mLeScanClients; @@ -655,8 +649,9 @@ public final class BluetoothAdapter { if (address == null || address.length != 6) { throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); } - return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", - address[0], address[1], address[2], address[3], address[4], address[5])); + return new BluetoothDevice( + String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], + address[2], address[3], address[4], address[5])); } /** @@ -668,7 +663,9 @@ public final class BluetoothAdapter { * on this device before calling this method. */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { - if (!getLeAccess()) return null; + if (!getLeAccess()) { + return null; + } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); @@ -698,8 +695,7 @@ public final class BluetoothAdapter { synchronized (mLock) { if (sPeriodicAdvertisingManager == null) { - sPeriodicAdvertisingManager = - new PeriodicAdvertisingManager(mManagerService); + sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService); } } return sPeriodicAdvertisingManager; @@ -709,7 +705,9 @@ public final class BluetoothAdapter { * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ public BluetoothLeScanner getBluetoothLeScanner() { - if (!getLeAccess()) return null; + if (!getLeAccess()) { + return null; + } synchronized (mLock) { if (sBluetoothLeScanner == null) { sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); @@ -729,7 +727,9 @@ public final class BluetoothAdapter { public boolean isEnabled() { try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isEnabled(); + if (mService != null) { + return mService.isEnabled(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -750,7 +750,9 @@ public final class BluetoothAdapter { @SystemApi public boolean isLeEnabled() { final int state = getLeState(); - if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + if (DBG) { + Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + } return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); } @@ -781,12 +783,16 @@ public final class BluetoothAdapter { */ @SystemApi public boolean disableBLE() { - if (!isBleScanAlwaysAvailable()) return false; + if (!isBleScanAlwaysAvailable()) { + return false; + } int state = getLeState(); if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { String packageName = ActivityThread.currentPackageName(); - if (DBG) Log.d(TAG, "disableBLE(): de-registering " + packageName); + if (DBG) { + Log.d(TAG, "disableBLE(): de-registering " + packageName); + } try { mManagerService.updateBleAppCount(mToken, false, packageName); } catch (RemoteException e) { @@ -795,7 +801,9 @@ public final class BluetoothAdapter { return true; } - if (DBG) Log.d(TAG, "disableBLE(): Already disabled"); + if (DBG) { + Log.d(TAG, "disableBLE(): Already disabled"); + } return false; } @@ -832,16 +840,22 @@ public final class BluetoothAdapter { */ @SystemApi public boolean enableBLE() { - if (!isBleScanAlwaysAvailable()) return false; + if (!isBleScanAlwaysAvailable()) { + return false; + } try { String packageName = ActivityThread.currentPackageName(); mManagerService.updateBleAppCount(mToken, true, packageName); if (isLeEnabled()) { - if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + if (DBG) { + Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + } return true; } - if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); + if (DBG) { + Log.d(TAG, "enableBLE(): Calling enable"); + } return mManagerService.enable(packageName); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -877,19 +891,16 @@ public final class BluetoothAdapter { } // Consider all internal states as OFF - if (state == BluetoothAdapter.STATE_BLE_ON - || state == BluetoothAdapter.STATE_BLE_TURNING_ON + if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { if (VDBG) { - Log.d(TAG, - "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); + Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); } state = BluetoothAdapter.STATE_OFF; } if (VDBG) { - Log.d(TAG, - "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( - state)); + Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( + state)); } return state; } @@ -926,7 +937,9 @@ public final class BluetoothAdapter { mServiceLock.readLock().unlock(); } - if (VDBG) Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); + if (VDBG) { + Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); + } return state; } @@ -967,7 +980,9 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { if (isEnabled()) { - if (DBG) Log.d(TAG, "enable(): BT already enabled!"); + if (DBG) { + Log.d(TAG, "enable(): BT already enabled!"); + } return true; } try { @@ -1093,10 +1108,14 @@ public final class BluetoothAdapter { * @hide */ public ParcelUuid[] getUuids() { - if (getState() != STATE_ON) return null; + if (getState() != STATE_ON) { + return null; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getUuids(); + if (mService != null) { + return mService.getUuids(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1121,10 +1140,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String name) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setName(name); + if (mService != null) { + return mService.setName(name); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1143,10 +1166,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public BluetoothClass getBluetoothClass() { - if (getState() != STATE_ON) return null; + if (getState() != STATE_ON) { + return null; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getBluetoothClass(); + if (mService != null) { + return mService.getBluetoothClass(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1168,10 +1195,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBluetoothClass(BluetoothClass bluetoothClass) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setBluetoothClass(bluetoothClass); + if (mService != null) { + return mService.setBluetoothClass(bluetoothClass); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1198,10 +1229,14 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @ScanMode public int getScanMode() { - if (getState() != STATE_ON) return SCAN_MODE_NONE; + if (getState() != STATE_ON) { + return SCAN_MODE_NONE; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getScanMode(); + if (mService != null) { + return mService.getScanMode(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1239,10 +1274,14 @@ public final class BluetoothAdapter { * @hide */ public boolean setScanMode(@ScanMode int mode, int duration) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setScanMode(mode, duration); + if (mService != null) { + return mService.setScanMode(mode, duration); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1253,17 +1292,23 @@ public final class BluetoothAdapter { /** @hide */ public boolean setScanMode(int mode) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } /* getDiscoverableTimeout() to use the latest from NV than use 0 */ return setScanMode(mode, getDiscoverableTimeout()); } /** @hide */ public int getDiscoverableTimeout() { - if (getState() != STATE_ON) return -1; + if (getState() != STATE_ON) { + return -1; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getDiscoverableTimeout(); + if (mService != null) { + return mService.getDiscoverableTimeout(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1274,10 +1319,14 @@ public final class BluetoothAdapter { /** @hide */ public void setDiscoverableTimeout(int timeout) { - if (getState() != STATE_ON) return; + if (getState() != STATE_ON) { + return; + } try { mServiceLock.readLock().lock(); - if (mService != null) mService.setDiscoverableTimeout(timeout); + if (mService != null) { + mService.setDiscoverableTimeout(timeout); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1296,7 +1345,9 @@ public final class BluetoothAdapter { public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getDiscoveryEndMillis(); + if (mService != null) { + return mService.getDiscoveryEndMillis(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1336,10 +1387,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.startDiscovery(); + if (mService != null) { + return mService.startDiscovery(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1366,10 +1421,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.cancelDiscovery(); + if (mService != null) { + return mService.cancelDiscovery(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1398,10 +1457,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isDiscovering() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isDiscovering(); + if (mService != null) { + return mService.isDiscovering(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1416,10 +1479,14 @@ public final class BluetoothAdapter { * @return true if Multiple Advertisement feature is supported */ public boolean isMultipleAdvertisementSupported() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isMultiAdvertisementSupported(); + if (mService != null) { + return mService.isMultiAdvertisementSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); } finally { @@ -1454,10 +1521,14 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip filtering */ public boolean isOffloadedFilteringSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isOffloadedFilteringSupported(); + if (mService != null) { + return mService.isOffloadedFilteringSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); } finally { @@ -1472,10 +1543,14 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip scan batching */ public boolean isOffloadedScanBatchingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isOffloadedScanBatchingSupported(); + if (mService != null) { + return mService.isOffloadedScanBatchingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); } finally { @@ -1490,10 +1565,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE 2M PHY feature */ public boolean isLe2MPhySupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLe2MPhySupported(); + if (mService != null) { + return mService.isLe2MPhySupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e); } finally { @@ -1508,10 +1587,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Coded PHY feature */ public boolean isLeCodedPhySupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLeCodedPhySupported(); + if (mService != null) { + return mService.isLeCodedPhySupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e); } finally { @@ -1526,10 +1609,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Extended Advertising feature */ public boolean isLeExtendedAdvertisingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLeExtendedAdvertisingSupported(); + if (mService != null) { + return mService.isLeExtendedAdvertisingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e); } finally { @@ -1544,10 +1631,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Periodic Advertising feature */ public boolean isLePeriodicAdvertisingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLePeriodicAdvertisingSupported(); + if (mService != null) { + return mService.isLePeriodicAdvertisingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e); } finally { @@ -1563,10 +1654,14 @@ public final class BluetoothAdapter { * @return the maximum LE advertising data length. */ public int getLeMaximumAdvertisingDataLength() { - if (!getLeAccess()) return 0; + if (!getLeAccess()) { + return 0; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeMaximumAdvertisingDataLength(); + if (mService != null) { + return mService.getLeMaximumAdvertisingDataLength(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); } finally { @@ -1582,7 +1677,9 @@ public final class BluetoothAdapter { * @hide */ public boolean isHardwareTrackingFiltersAvailable() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { @@ -1669,7 +1766,9 @@ public final class BluetoothAdapter { } try { mServiceLock.readLock().lock(); - if (mService != null) return toDeviceSet(mService.getBondedDevices()); + if (mService != null) { + return toDeviceSet(mService.getBondedDevices()); + } return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1723,10 +1822,14 @@ public final class BluetoothAdapter { * @hide */ public int getConnectionState() { - if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; + if (getState() != STATE_ON) { + return BluetoothAdapter.STATE_DISCONNECTED; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getAdapterConnectionState(); + if (mService != null) { + return mService.getAdapterConnectionState(); + } } catch (RemoteException e) { Log.e(TAG, "getConnectionState:", e); } finally { @@ -1750,10 +1853,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int profile) { - if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; + if (getState() != STATE_ON) { + return BluetoothProfile.STATE_DISCONNECTED; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getProfileConnectionState(profile); + if (mService != null) { + return mService.getProfileConnectionState(profile); + } } catch (RemoteException e) { Log.e(TAG, "getProfileConnectionState:", e); } finally { @@ -1790,7 +1897,7 @@ public final class BluetoothAdapter { * <p>Valid RFCOMM channels are in range 1 to 30. * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * <p>To auto assign a channel without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. * * @param channel RFCOMM channel to listen on * @param mitm enforce man-in-the-middle protection for authentication. @@ -1802,10 +1909,10 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, - boolean min16DigitPin) - throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin); + boolean min16DigitPin) throws IOException { + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, + min16DigitPin); int errno = socket.mSocket.bindListen(); if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1913,8 +2020,8 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( - String name, UUID uuid) throws IOException { + public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) + throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); } @@ -1922,8 +2029,8 @@ public final class BluetoothAdapter { private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { BluetoothServerSocket socket; - socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, - encrypt, new ParcelUuid(uuid)); + socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt, + new ParcelUuid(uuid)); socket.setServiceName(name); int errno = socket.mSocket.bindListen(); if (errno != 0) { @@ -1945,8 +2052,8 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, false, false, port); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1969,10 +2076,9 @@ public final class BluetoothAdapter { * permissions. * @hide */ - public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) - throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, false, true, port); + public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1996,8 +2102,8 @@ public final class BluetoothAdapter { * @hide */ public static BluetoothServerSocket listenUsingScoOn() throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_SCO, false, false, -1); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1); int errno = socket.mSocket.bindListen(); if (errno < 0) { //TODO(BT): Throw the same exception error code @@ -2011,7 +2117,7 @@ public final class BluetoothAdapter { * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. * <p>To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @param mitm enforce man-in-the-middle protection for authentication. @@ -2024,8 +2130,9 @@ public final class BluetoothAdapter { */ public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, + min16DigitPin); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -2043,7 +2150,7 @@ public final class BluetoothAdapter { * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. * <p>To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket @@ -2060,7 +2167,7 @@ public final class BluetoothAdapter { * Construct an insecure L2CAP server socket. * Call #accept to retrieve connections to this socket. * <p>To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket @@ -2069,8 +2176,9 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, false, false, port, false, false); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, + false); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -2114,7 +2222,9 @@ public final class BluetoothAdapter { */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile) { - if (context == null || listener == null) return false; + if (context == null || listener == null) { + return false; + } if (profile == BluetoothProfile.HEADSET) { BluetoothHeadset headset = new BluetoothHeadset(context, listener); @@ -2172,7 +2282,9 @@ public final class BluetoothAdapter { * @param proxy Profile proxy object */ public void closeProfileProxy(int profile, BluetoothProfile proxy) { - if (proxy == null) return; + if (proxy == null) { + return; + } switch (profile) { case BluetoothProfile.HEADSET: @@ -2241,7 +2353,9 @@ public final class BluetoothAdapter { private final IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + if (DBG) { + Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + } mServiceLock.writeLock().lock(); mService = bluetoothService; @@ -2263,14 +2377,22 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + if (DBG) { + Log.d(TAG, "onBluetoothServiceDown: " + mService); + } try { mServiceLock.writeLock().lock(); mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + if (mLeScanClients != null) { + mLeScanClients.clear(); + } + if (sBluetoothLeAdvertiser != null) { + sBluetoothLeAdvertiser.cleanup(); + } + if (sBluetoothLeScanner != null) { + sBluetoothLeScanner.cleanup(); + } } finally { mServiceLock.writeLock().unlock(); } @@ -2291,7 +2413,9 @@ public final class BluetoothAdapter { } public void onBrEdrDown() { - if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService); + if (VDBG) { + Log.i(TAG, "onBrEdrDown: " + mService); + } } }; @@ -2305,7 +2429,9 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect() { if (isEnabled()) { - if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); + if (DBG) { + Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); + } return true; } try { @@ -2354,7 +2480,10 @@ public final class BluetoothAdapter { * @hide */ public interface BluetoothStateChangeCallback { - public void onBluetoothStateChange(boolean on); + /** + * @hide + */ + void onBluetoothStateChange(boolean on); } /** @@ -2363,8 +2492,7 @@ public final class BluetoothAdapter { public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; - StateChangeCallbackWrapper(BluetoothStateChangeCallback - callback) { + StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { mCallback = callback; } @@ -2461,7 +2589,7 @@ public final class BluetoothAdapter { * if no RSSI value is available. * @param scanRecord The content of the advertisement record offered by the remote device. */ - public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); + void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } /** @@ -2497,20 +2625,28 @@ public final class BluetoothAdapter { @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { - if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); + if (DBG) { + Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); + } if (callback == null) { - if (DBG) Log.e(TAG, "startLeScan: null callback"); + if (DBG) { + Log.e(TAG, "startLeScan: null callback"); + } return false; } BluetoothLeScanner scanner = getBluetoothLeScanner(); if (scanner == null) { - if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + if (DBG) { + Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + } return false; } synchronized (mLeScanClients) { if (mLeScanClients.containsKey(callback)) { - if (DBG) Log.e(TAG, "LE Scan has already started"); + if (DBG) { + Log.e(TAG, "LE Scan has already started"); + } return false; } @@ -2540,7 +2676,9 @@ public final class BluetoothAdapter { } List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids(); if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { - if (DBG) Log.d(TAG, "uuids does not match"); + if (DBG) { + Log.d(TAG, "uuids does not match"); + } return; } } @@ -2548,16 +2686,18 @@ public final class BluetoothAdapter { scanRecord.getBytes()); } }; - ScanSettings settings = new ScanSettings.Builder() - .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); + ScanSettings settings = new ScanSettings.Builder().setCallbackType( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .build(); List<ScanFilter> filters = new ArrayList<ScanFilter>(); if (serviceUuids != null && serviceUuids.length > 0) { // Note scan filter does not support matching an UUID array so we put one // UUID to hardware and match the whole array in callback. - ScanFilter filter = new ScanFilter.Builder().setServiceUuid( - new ParcelUuid(serviceUuids[0])).build(); + ScanFilter filter = + new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0])) + .build(); filters.add(filter); } scanner.startScan(filters, settings, scanCallback); @@ -2582,7 +2722,9 @@ public final class BluetoothAdapter { @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(LeScanCallback callback) { - if (DBG) Log.d(TAG, "stopLeScan()"); + if (DBG) { + Log.d(TAG, "stopLeScan()"); + } BluetoothLeScanner scanner = getBluetoothLeScanner(); if (scanner == null) { return; @@ -2590,7 +2732,9 @@ public final class BluetoothAdapter { synchronized (mLeScanClients) { ScanCallback scanCallback = mLeScanClients.remove(callback); if (scanCallback == null) { - if (DBG) Log.d(TAG, "scan not started yet"); + if (DBG) { + Log.d(TAG, "scan not started yet"); + } return; } scanner.stopScan(scanCallback); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 71998eeb14c7..9800ab0041b7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2801,10 +2801,17 @@ public abstract class Context { * example, if this Context is an Activity that is stopped, the service will * not be required to continue running until the Activity is resumed. * - * <p>This function will throw {@link SecurityException} if you do not + * <p>If the service does not support binding, it may return {@code null} from + * its {@link android.app.Service#onBind(Intent) onBind()} method. If it does, then + * the ServiceConnection's + * {@link ServiceConnection#onNullBinding(ComponentName) onNullBinding()} method + * will be invoked instead of + * {@link ServiceConnection#onServiceConnected(ComponentName, IBinder) onServiceConnected()}. + * + * <p>This method will throw {@link SecurityException} if the calling app does not * have permission to bind to the given service. * - * <p class="note">Note: this method <em>can not be called from a + * <p class="note">Note: this method <em>cannot be called from a * {@link BroadcastReceiver} component</em>. A pattern you can use to * communicate from a BroadcastReceiver to a Service is to call * {@link #startService} with the arguments containing the command to be @@ -2827,8 +2834,8 @@ public abstract class Context { * {@link #BIND_WAIVE_PRIORITY}. * @return If you have successfully bound to the service, {@code true} is returned; * {@code false} is returned if the connection is not made so you will not - * receive the service object. However, you should still call - * {@link #unbindService} to release the connection. + * receive the service object. You should still call {@link #unbindService} + * to release the connection even if this method returned {@code false}. * * @throws SecurityException If the caller does not have permission to access the service * or the service can not be found. @@ -3406,6 +3413,14 @@ public abstract class Context { public static final String NETWORKMANAGEMENT_SERVICE = "network_management"; /** + * Use with {@link #getSystemService} to retrieve a + * {@link com.android.server.slice.SliceManagerService} for managing slices. + * @hide + * @see #getSystemService + */ + public static final String SLICE_SERVICE = "slice"; + + /** * Use with {@link #getSystemService} to retrieve a {@link * android.app.usage.NetworkStatsManager} for querying network usage stats. * diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 55ad5c5dd1b6..28bd928214ae 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4461,6 +4461,16 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION"; /** + * A {@link Bundle} of metadata that describes the instanta application that needs to be + * installed. This data is populated from the response to + * {@link android.content.pm.InstantAppResolveInfo#getExtras()} as provided by the registered + * instant application resolver. + * @hide + */ + public static final String EXTRA_INSTANT_APP_EXTRAS = + "android.intent.extra.INSTANT_APP_EXTRAS"; + + /** * The version code of the app to install components from. * @deprecated Use {@link #EXTRA_LONG_VERSION_CODE). * @hide diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java index 6ff4900212ff..c16dbbe33aab 100644 --- a/core/java/android/content/ServiceConnection.java +++ b/core/java/android/content/ServiceConnection.java @@ -63,4 +63,21 @@ public interface ServiceConnection { */ default void onBindingDied(ComponentName name) { } + + /** + * Called when the service being bound has returned {@code null} from its + * {@link android.app.Service#onBind(Intent) onBind()} method. This indicates + * that the attempting service binding represented by this ServiceConnection + * will never become usable. + * + * <p class="note">The app which requested the binding must still call + * {@link Context#unbindService(ServiceConnection)} to release the tracking + * resources associated with this ServiceConnection even if this callback was + * invoked following {@link Context#bindService Context.bindService() bindService()}. + * + * @param name The concrete component name of the service whose binding + * has been rejected by the Service implementation. + */ + default void onNullBinding(ComponentName name) { + } } diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java index fb3094c70953..19cb9323ba93 100644 --- a/core/java/android/content/pm/InstantAppResolveInfo.java +++ b/core/java/android/content/pm/InstantAppResolveInfo.java @@ -19,8 +19,7 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.content.IntentFilter; -import android.net.Uri; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -45,14 +44,17 @@ public final class InstantAppResolveInfo implements Parcelable { private final List<InstantAppIntentFilter> mFilters; /** The version code of the app that this class resolves to */ private final long mVersionCode; + /** Data about the app that should be passed along to the Instant App installer on resolve */ + private final Bundle mExtras; public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName, @Nullable List<InstantAppIntentFilter> filters, int versionCode) { - this(digest, packageName, filters, (long)versionCode); + this(digest, packageName, filters, (long) versionCode, null /* extras */); } public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName, - @Nullable List<InstantAppIntentFilter> filters, long versionCode) { + @Nullable List<InstantAppIntentFilter> filters, long versionCode, + @Nullable Bundle extras) { // validate arguments if ((packageName == null && (filters != null && filters.size() != 0)) || (packageName != null && (filters == null || filters.size() == 0))) { @@ -67,11 +69,13 @@ public final class InstantAppResolveInfo implements Parcelable { } mPackageName = packageName; mVersionCode = versionCode; + mExtras = extras; } public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName, @Nullable List<InstantAppIntentFilter> filters) { - this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/); + this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/, + null /* extras */); } InstantAppResolveInfo(Parcel in) { @@ -80,6 +84,7 @@ public final class InstantAppResolveInfo implements Parcelable { mFilters = new ArrayList<InstantAppIntentFilter>(); in.readList(mFilters, null /*loader*/); mVersionCode = in.readLong(); + mExtras = in.readBundle(); } public byte[] getDigestBytes() { @@ -110,6 +115,11 @@ public final class InstantAppResolveInfo implements Parcelable { return mVersionCode; } + @Nullable + public Bundle getExtras() { + return mExtras; + } + @Override public int describeContents() { return 0; @@ -121,6 +131,7 @@ public final class InstantAppResolveInfo implements Parcelable { out.writeString(mPackageName); out.writeList(mFilters); out.writeLong(mVersionCode); + out.writeBundle(mExtras); } public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR diff --git a/core/java/android/content/pm/crossprofile/CrossProfileApps.java b/core/java/android/content/pm/crossprofile/CrossProfileApps.java index c441b5f376a0..c9f184a7da53 100644 --- a/core/java/android/content/pm/crossprofile/CrossProfileApps.java +++ b/core/java/android/content/pm/crossprofile/CrossProfileApps.java @@ -19,12 +19,17 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import com.android.internal.R; +import com.android.internal.util.UserIcons; + import java.util.List; /** @@ -35,11 +40,15 @@ import java.util.List; public class CrossProfileApps { private final Context mContext; private final ICrossProfileApps mService; + private final UserManager mUserManager; + private final Resources mResources; /** @hide */ public CrossProfileApps(Context context, ICrossProfileApps service) { mContext = context; mService = service; + mUserManager = context.getSystemService(UserManager.class); + mResources = context.getResources(); } /** @@ -87,4 +96,58 @@ public class CrossProfileApps { throw ex.rethrowFromSystemServer(); } } + + /** + * Return a label that calling app can show to user for the semantic of profile switching -- + * launching its own activity in specified user profile. For example, it may return + * "Switch to work" if the given user handle is the managed profile one. + * + * @param userHandle The UserHandle of the target profile, must be one of the users returned by + * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will + * be thrown. + * @return a label that calling app can show user for the semantic of launching its own + * activity in the specified user profile. + * + * @see #startMainActivity(ComponentName, UserHandle, Rect, Bundle) + */ + public @NonNull CharSequence getProfileSwitchingLabel(@NonNull UserHandle userHandle) { + verifyCanAccessUser(userHandle); + + final int stringRes = mUserManager.isManagedProfile(userHandle.getIdentifier()) + ? R.string.managed_profile_label + : R.string.user_owner_label; + return mResources.getString(stringRes); + } + + /** + * Return an icon that calling app can show to user for the semantic of profile switching -- + * launching its own activity in specified user profile. For example, it may return a briefcase + * icon if the given user handle is the managed profile one. + * + * @param userHandle The UserHandle of the target profile, must be one of the users returned by + * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will + * be thrown. + * @return an icon that calling app can show user for the semantic of launching its own + * activity in specified user profile. + * + * @see #startMainActivity(ComponentName, UserHandle, Rect, Bundle) + */ + public @NonNull Drawable getProfileSwitchingIcon(@NonNull UserHandle userHandle) { + verifyCanAccessUser(userHandle); + + final boolean isManagedProfile = + mUserManager.isManagedProfile(userHandle.getIdentifier()); + if (isManagedProfile) { + return mResources.getDrawable(R.drawable.ic_corp_badge, null); + } else { + return UserIcons.getDefaultUserIcon( + mResources, UserHandle.USER_SYSTEM, true /* light */); + } + } + + private void verifyCanAccessUser(UserHandle userHandle) { + if (!getTargetUserProfiles().contains(userHandle)) { + throw new SecurityException("Not allowed to access " + userHandle); + } + } } diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java index fe24e32e3e62..3003607e5f72 100644 --- a/core/java/android/hardware/display/BrightnessChangeEvent.java +++ b/core/java/android/hardware/display/BrightnessChangeEvent.java @@ -21,6 +21,8 @@ import android.os.Parcelable; /** * Data about a brightness settings change. + * + * {@see DisplayManager.getBrightnessEvents()} * TODO make this SystemAPI * @hide */ @@ -31,7 +33,9 @@ public final class BrightnessChangeEvent implements Parcelable { /** Timestamp of the change {@see System.currentTimeMillis()} */ public long timeStamp; - /** Package name of focused activity when brightness was changed. */ + /** Package name of focused activity when brightness was changed. + * This will be null if the caller of {@see DisplayManager.getBrightnessEvents()} + * does not have access to usage stats {@see UsageStatsManager} */ public String packageName; /** User id of of the user running when brightness was changed. @@ -59,6 +63,20 @@ public final class BrightnessChangeEvent implements Parcelable { public BrightnessChangeEvent() { } + /** @hide */ + public BrightnessChangeEvent(BrightnessChangeEvent other) { + this.brightness = other.brightness; + this.timeStamp = other.timeStamp; + this.packageName = other.packageName; + this.userId = other.userId; + this.luxValues = other.luxValues; + this.luxTimestamps = other.luxTimestamps; + this.batteryLevel = other.batteryLevel; + this.nightMode = other.nightMode; + this.colorTemperature = other.colorTemperature; + this.lastBrightness = other.lastBrightness; + } + private BrightnessChangeEvent(Parcel source) { brightness = source.readInt(); timeStamp = source.readLong(); diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 89357456053c..97ca231bf68c 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -16,8 +16,10 @@ package android.hardware.display; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.KeyguardManager; @@ -619,8 +621,9 @@ public final class DisplayManager { * Fetch {@link BrightnessChangeEvent}s. * @hide until we make it a system api. */ + @RequiresPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public List<BrightnessChangeEvent> getBrightnessEvents() { - return mGlobal.getBrightnessEvents(); + return mGlobal.getBrightnessEvents(mContext.getOpPackageName()); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index d93d0e4ed135..c3f82f56dad8 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -462,9 +462,10 @@ public final class DisplayManagerGlobal { /** * Retrieves brightness change events. */ - public List<BrightnessChangeEvent> getBrightnessEvents() { + public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { try { - ParceledListSlice<BrightnessChangeEvent> events = mDm.getBrightnessEvents(); + ParceledListSlice<BrightnessChangeEvent> events = + mDm.getBrightnessEvents(callingPackage); if (events == null) { return Collections.emptyList(); } diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index b796cf9aa77b..f2ed9e7571d3 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -84,7 +84,7 @@ interface IDisplayManager { Point getStableDisplaySize(); // Requires BRIGHTNESS_SLIDER_USAGE permission. - ParceledListSlice getBrightnessEvents(); + ParceledListSlice getBrightnessEvents(String callingPackage); // STOPSHIP remove when adaptive brightness code is updated to accept curves. // Requires BRIGHTNESS_SLIDER_USAGE permission. diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 7836cd0952aa..13b9206b12ee 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -21,16 +21,18 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; -import android.graphics.Paint.Align; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.Region.Op; import android.graphics.Typeface; +import android.graphics.Paint.Align; +import android.graphics.Region.Op; import android.graphics.drawable.Drawable; import android.inputmethodservice.Keyboard.Key; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.os.UserHandle; +import android.provider.Settings; import android.util.AttributeSet; import android.util.TypedValue; import android.view.GestureDetector; @@ -984,9 +986,6 @@ public class KeyboardView extends View implements View.OnClickListener { private void sendAccessibilityEventForUnicodeCharacter(int eventType, int code) { if (mAccessibilityManager.isEnabled()) { - if (!mAccessibilityManager.isObservedEventType(eventType)) { - return; - } AccessibilityEvent event = AccessibilityEvent.obtain(eventType); onInitializeAccessibilityEvent(event); final String text; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index f977c1dea438..b1794a6dfa6c 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -24,6 +24,7 @@ import android.text.TextUtils; import android.util.Log; import java.io.File; +import java.util.LinkedList; /** * Provides access to environment variables. @@ -291,8 +292,9 @@ public class Environment { } /** {@hide} */ - public static File getReferenceProfile(String packageName) { - return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); + public static File getProfileSnapshotPath(String packageName, String codePath) { + return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName, + "primary.prof.snapshot")); } /** {@hide} */ @@ -608,6 +610,79 @@ public class Environment { return false; } + /** {@hide} */ public static final int HAS_MUSIC = 1 << 0; + /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1; + /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2; + /** {@hide} */ public static final int HAS_ALARMS = 1 << 3; + /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4; + /** {@hide} */ public static final int HAS_PICTURES = 1 << 5; + /** {@hide} */ public static final int HAS_MOVIES = 1 << 6; + /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7; + /** {@hide} */ public static final int HAS_DCIM = 1 << 8; + /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9; + + /** {@hide} */ public static final int HAS_ANDROID = 1 << 16; + /** {@hide} */ public static final int HAS_OTHER = 1 << 17; + + /** + * Classify the content types present on the given external storage device. + * <p> + * This is typically useful for deciding if an inserted SD card is empty, or + * if it contains content like photos that should be preserved. + * + * @hide + */ + public static int classifyExternalStorageDirectory(File dir) { + int res = 0; + for (File f : FileUtils.listFilesOrEmpty(dir)) { + if (f.isFile() && isInterestingFile(f)) { + res |= HAS_OTHER; + } else if (f.isDirectory() && hasInterestingFiles(f)) { + final String name = f.getName(); + if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC; + else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS; + else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES; + else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS; + else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS; + else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES; + else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES; + else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS; + else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM; + else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS; + else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID; + else res |= HAS_OTHER; + } + } + return res; + } + + private static boolean hasInterestingFiles(File dir) { + final LinkedList<File> explore = new LinkedList<>(); + explore.add(dir); + while (!explore.isEmpty()) { + dir = explore.pop(); + for (File f : FileUtils.listFilesOrEmpty(dir)) { + if (isInterestingFile(f)) return true; + if (f.isDirectory()) explore.add(f); + } + } + return false; + } + + private static boolean isInterestingFile(File file) { + if (file.isFile()) { + final String name = file.getName().toLowerCase(); + if (name.endsWith(".exe") || name.equals("autorun.inf") + || name.equals("launchpad.zip") || name.equals(".nomedia")) { + return false; + } else { + return true; + } + } else { + return false; + } + } + /** * Get a top-level shared/external storage directory for placing files of a * particular type. This is where the user will typically place and manage diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index 9491bec6532c..3ec744dabb81 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -33,6 +33,8 @@ public final class StatsLogEventWrapper implements Parcelable { private static final int EVENT_TYPE_LIST = 3; private static final int EVENT_TYPE_FLOAT = 4; + // Keep this in sync with system/core/logcat/event.logtags + private static final int STATS_BUFFER_TAG_ID = 1937006964; /** * Creates a log_event that is binary-encoded as implemented in * system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd @@ -46,9 +48,14 @@ public final class StatsLogEventWrapper implements Parcelable { */ public StatsLogEventWrapper(int tag, int fields) { // Write four bytes from tag, starting with least-significant bit. - write4Bytes(tag); + // For pulled data, this tag number is not really used. We use the same tag number as + // pushed ones to be consistent. + write4Bytes(STATS_BUFFER_TAG_ID); mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry. mStorage.write(fields); // Indicate number of elements in this list. + mStorage.write(EVENT_TYPE_INT); + // The first element is the real atom tag number + write4Bytes(tag); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5505f597afb7..1d4477a1c4c1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5330,11 +5330,12 @@ public final class Settings { /** * Experimental autofill feature. * - * <p>TODO(b/67867469): remove once feature is finished + * <p>TODO(b/67867469): document (or remove) once feature is finished * @hide */ @TestApi - public static final String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection"; + public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = + "autofill_field_classification"; /** * Experimental autofill feature. @@ -9570,8 +9571,8 @@ public final class Settings { * The following keys are supported: * * <pre> - * screen_brightness_array (string) - * dimming_scrim_array (string) + * screen_brightness_array (int[]) + * dimming_scrim_array (int[]) * prox_screen_off_delay (long) * prox_cooldown_trigger (long) * prox_cooldown_period (long) @@ -10543,6 +10544,15 @@ public final class Settings { SOFT_AP_TIMEOUT_ENABLED }; + /** + * Global settings that shouldn't be persisted. + * + * @hide + */ + public static final String[] TRANSIENT_SETTINGS = { + LOCATION_GLOBAL_KILL_SWITCH, + }; + /** @hide */ public static final String[] LEGACY_RESTORE_SETTINGS = { }; @@ -11114,7 +11124,7 @@ public final class Settings { * * <pre> * default (int) - * options_array (string) + * options_array (int[]) * </pre> * * All delays in integer minutes. Array order is respected. diff --git a/core/java/android/service/autofill/EditDistanceScorer.java b/core/java/android/service/autofill/EditDistanceScorer.java new file mode 100644 index 000000000000..e25cd0467cc8 --- /dev/null +++ b/core/java/android/service/autofill/EditDistanceScorer.java @@ -0,0 +1,103 @@ +/* + * 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.service.autofill; + +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.AutofillValue; + +/** + * Helper used to calculate the classification score between an actual {@link AutofillValue} filled + * by the user and the expected value predicted by an autofill service. + * + * TODO(b/67867469): + * - improve javadoc + * - document algorithm / copy from InternalScorer + * - unhide / remove testApi + * @hide + */ +@TestApi +public final class EditDistanceScorer extends InternalScorer implements Scorer, Parcelable { + + private static final EditDistanceScorer sInstance = new EditDistanceScorer(); + + /** + * Gets the singleton instance. + */ + public static EditDistanceScorer getInstance() { + return sInstance; + } + + private EditDistanceScorer() { + } + + @Override + public float getScore(@NonNull AutofillValue actualValue, @NonNull String userData) { + if (actualValue == null || !actualValue.isText() || userData == null) return 0; + // TODO(b/67867469): implement edit distance - currently it's returning either 0, 100%, or + // partial match when number of chars match + final String textValue = actualValue.getTextValue().toString(); + final int total = textValue.length(); + if (total != userData.length()) return 0F; + + int matches = 0; + for (int i = 0; i < total; i++) { + if (Character.toLowerCase(textValue.charAt(i)) == Character + .toLowerCase(userData.charAt(i))) { + matches++; + } + } + + return ((float) matches) / total; + } + + ///////////////////////////////////// + // Object "contract" methods. // + ///////////////////////////////////// + @Override + public String toString() { + return "EditDistanceScorer"; + } + + ///////////////////////////////////// + // Parcelable "contract" methods. // + ///////////////////////////////////// + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + // Do nothing + } + + public static final Parcelable.Creator<EditDistanceScorer> CREATOR = + new Parcelable.Creator<EditDistanceScorer>() { + @Override + public EditDistanceScorer createFromParcel(Parcel parcel) { + return EditDistanceScorer.getInstance(); + } + + @Override + public EditDistanceScorer[] newArray(int size) { + return new EditDistanceScorer[size]; + } + }; +} diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java new file mode 100644 index 000000000000..0a60208c45a7 --- /dev/null +++ b/core/java/android/service/autofill/FieldClassification.java @@ -0,0 +1,192 @@ +/* + * 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.service.autofill; + +import static android.view.autofill.Helper.sDebug; + +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.Helper; + +import com.android.internal.util.Preconditions; + +import com.google.android.collect.Lists; + +import java.util.List; + +/** + * Gets the <a href="#FieldsClassification">fields classification</a> results for a given field. + * + * TODO(b/67867469): + * - improve javadoc + * - unhide / remove testApi + * + * @hide + */ +@TestApi +public final class FieldClassification implements Parcelable { + + private final Match mMatch; + + /** @hide */ + public FieldClassification(@NonNull Match match) { + mMatch = Preconditions.checkNotNull(match); + } + + /** + * Gets the {@link Match matches} with the highest {@link Match#getScore() scores}. + * + * <p><b>Note:</b> There's no guarantee of how many matches will be returned. In fact, + * the Android System might return just the top match to minimize the impact of field + * classification in the device's health. + */ + @NonNull + public List<Match> getMatches() { + return Lists.newArrayList(mMatch); + } + + @Override + public String toString() { + if (!sDebug) return super.toString(); + + return "FieldClassification: " + mMatch; + } + + ///////////////////////////////////// + // Parcelable "contract" methods. // + ///////////////////////////////////// + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mMatch, flags); + } + + public static final Parcelable.Creator<FieldClassification> CREATOR = + new Parcelable.Creator<FieldClassification>() { + + @Override + public FieldClassification createFromParcel(Parcel parcel) { + return new FieldClassification(parcel.readParcelable(null)); + } + + @Override + public FieldClassification[] newArray(int size) { + return new FieldClassification[size]; + } + }; + + /** + * Gets the score of a {@link UserData} entry for the field. + * + * TODO(b/67867469): + * - improve javadoc + * - unhide / remove testApi + * + * @hide + */ + @TestApi + public static final class Match implements Parcelable { + + private final String mRemoteId; + private final float mScore; + + /** @hide */ + public Match(String remoteId, float score) { + mRemoteId = Preconditions.checkNotNull(remoteId); + mScore = score; + } + + /** + * Gets the remote id of the {@link UserData} entry. + */ + @NonNull + public String getRemoteId() { + return mRemoteId; + } + + /** + * Gets a score between the value of this field and the value of the {@link UserData} entry. + * + * <p>The score is based in a case-insensitive comparisson of all characters from both the + * field value and the user data entry, and it ranges from {@code 0} to {@code 1000000}: + * <ul> + * <li>{@code 1.0} represents a full match ({@code 100%}). + * <li>{@code 0.0} represents a full mismatch ({@code 0%}). + * <li>Any other value is a partial match. + * </ul> + * + * <p>How the score is calculated depends on the algorithm used by the Android System. + * For example, if the user data is {@code "abc"} and the field value us {@code " abc"}, + * the result could be: + * <ul> + * <li>{@code 1.0} if the algorithm trims the values. + * <li>{@code 0.0} if the algorithm compares the values sequentially. + * <li>{@code 0.75} if the algorithm consideres that 3/4 (75%) of the characters match. + * </ul> + * + * <p>Currently, the autofill service cannot configure the algorithm. + */ + public float getScore() { + return mScore; + } + + @Override + public String toString() { + if (!sDebug) return super.toString(); + + final StringBuilder string = new StringBuilder("Match: remoteId="); + Helper.appendRedacted(string, mRemoteId); + return string.append(", score=").append(mScore).toString(); + } + + ///////////////////////////////////// + // Parcelable "contract" methods. // + ///////////////////////////////////// + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mRemoteId); + parcel.writeFloat(mScore); + } + + @SuppressWarnings("hiding") + public static final Parcelable.Creator<Match> CREATOR = new Parcelable.Creator<Match>() { + + @Override + public Match createFromParcel(Parcel parcel) { + return new Match(parcel.readString(), parcel.readFloat()); + } + + @Override + public Match[] newArray(int size) { + return new Match[size]; + } + }; + } +} diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index eedb972e4ea6..facad2d1ab30 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -16,6 +16,8 @@ package android.service.autofill; +import static android.view.autofill.Helper.sVerbose; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -24,8 +26,10 @@ import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.service.autofill.FieldClassification.Match; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Log; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; @@ -35,6 +39,7 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -57,6 +62,8 @@ import java.util.Set; * the history will clear out after some pre-defined time). */ public final class FillEventHistory implements Parcelable { + private static final String TAG = "FillEventHistory"; + /** * Not in parcel. The ID of the autofill session that created the {@link FillResponse}. */ @@ -123,34 +130,35 @@ public final class FillEventHistory implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeBundle(mClientState); + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeBundle(mClientState); if (mEvents == null) { - dest.writeInt(0); + parcel.writeInt(0); } else { - dest.writeInt(mEvents.size()); + parcel.writeInt(mEvents.size()); int numEvents = mEvents.size(); for (int i = 0; i < numEvents; i++) { Event event = mEvents.get(i); - dest.writeInt(event.mEventType); - dest.writeString(event.mDatasetId); - dest.writeBundle(event.mClientState); - dest.writeStringList(event.mSelectedDatasetIds); - dest.writeArraySet(event.mIgnoredDatasetIds); - dest.writeTypedList(event.mChangedFieldIds); - dest.writeStringList(event.mChangedDatasetIds); - - dest.writeTypedList(event.mManuallyFilledFieldIds); + parcel.writeInt(event.mEventType); + parcel.writeString(event.mDatasetId); + parcel.writeBundle(event.mClientState); + parcel.writeStringList(event.mSelectedDatasetIds); + parcel.writeArraySet(event.mIgnoredDatasetIds); + parcel.writeTypedList(event.mChangedFieldIds); + parcel.writeStringList(event.mChangedDatasetIds); + + parcel.writeTypedList(event.mManuallyFilledFieldIds); if (event.mManuallyFilledFieldIds != null) { final int size = event.mManuallyFilledFieldIds.size(); for (int j = 0; j < size; j++) { - dest.writeStringList(event.mManuallyFilledDatasetIds.get(j)); + parcel.writeStringList(event.mManuallyFilledDatasetIds.get(j)); } } - dest.writeString(event.mDetectedRemoteId); - if (event.mDetectedRemoteId != null) { - dest.writeInt(event.mDetectedFieldScore); + final AutofillId[] detectedFields = event.mDetectedFieldIds; + parcel.writeParcelableArray(detectedFields, flags); + if (detectedFields != null) { + parcel.writeParcelableArray(event.mDetectedMatches, flags); } } } @@ -242,8 +250,8 @@ public final class FillEventHistory implements Parcelable { @Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds; @Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds; - @Nullable private final String mDetectedRemoteId; - private final int mDetectedFieldScore; + @Nullable private final AutofillId[] mDetectedFieldIds; + @Nullable private final Match[] mDetectedMatches; /** * Returns the type of the event. @@ -347,37 +355,33 @@ public final class FillEventHistory implements Parcelable { } /** - * Gets the results of the last fields classification request. - * - * @return map of edit-distance match ({@code 0} means full match, - * {@code 1} means 1 character different, etc...) by remote id (as set on - * {@link UserData.Builder#add(String, android.view.autofill.AutofillValue)}), - * or {@code null} if none of the user-input values - * matched the requested detection. + * Gets the <a href="#FieldsClassification">fields classification</a> results. * * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the * service requested {@link FillResponse.Builder#setFieldClassificationIds(AutofillId...) - * fields detection}. + * fields classification}. * * TODO(b/67867469): * - improve javadoc - * - refine score meaning (for example, should 1 be different of -1?) - * - mention when it's set - * - unhide * - unhide / remove testApi - * - add @NonNull / check it / add unit tests - * - add link to AutofillService #FieldsClassification anchor * * @hide */ @TestApi - @NonNull public Map<String, Integer> getFieldsClassification() { - if (mDetectedRemoteId == null || mDetectedFieldScore == -1) { + @NonNull public Map<AutofillId, FieldClassification> getFieldsClassification() { + if (mDetectedFieldIds == null) { return Collections.emptyMap(); } - - final ArrayMap<String, Integer> map = new ArrayMap<>(1); - map.put(mDetectedRemoteId, mDetectedFieldScore); + final int size = mDetectedFieldIds.length; + final ArrayMap<AutofillId, FieldClassification> map = new ArrayMap<>(size); + for (int i = 0; i < size; i++) { + final AutofillId id = mDetectedFieldIds[i]; + final Match match = mDetectedMatches[i]; + if (sVerbose) { + Log.v(TAG, "getFieldsClassification[" + i + "]: id=" + id + ", match=" + match); + } + map.put(id, new FieldClassification(match)); + } return map; } @@ -464,7 +468,7 @@ public final class FillEventHistory implements Parcelable { * * @hide */ - // TODO(b/67867469): document detection field parameters once stable + // TODO(b/67867469): document field classification parameters once stable public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState, @Nullable List<String> selectedDatasetIds, @Nullable ArraySet<String> ignoredDatasetIds, @@ -472,7 +476,7 @@ public final class FillEventHistory implements Parcelable { @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, - @Nullable String detectedRemoteId, int detectedFieldScore) { + @Nullable AutofillId[] detectedFieldIds, @Nullable Match[] detectedMaches) { mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED, "eventType"); mDatasetId = datasetId; @@ -495,8 +499,9 @@ public final class FillEventHistory implements Parcelable { } mManuallyFilledFieldIds = manuallyFilledFieldIds; mManuallyFilledDatasetIds = manuallyFilledDatasetIds; - mDetectedRemoteId = detectedRemoteId; - mDetectedFieldScore = detectedFieldScore; + + mDetectedFieldIds = detectedFieldIds; + mDetectedMatches = detectedMaches; } @Override @@ -509,8 +514,8 @@ public final class FillEventHistory implements Parcelable { + ", changedDatasetsIds=" + mChangedDatasetIds + ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds + ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds - + ", detectedRemoteId=" + mDetectedRemoteId - + ", detectedFieldScore=" + mDetectedFieldScore + + ", detectedFieldIds=" + Arrays.toString(mDetectedFieldIds) + + ", detectedMaches =" + Arrays.toString(mDetectedMatches) + "]"; } } @@ -546,15 +551,17 @@ public final class FillEventHistory implements Parcelable { } else { manuallyFilledDatasetIds = null; } - final String detectedRemoteId = parcel.readString(); - final int detectedFieldScore = detectedRemoteId == null ? -1 - : parcel.readInt(); + final AutofillId[] detectedFieldIds = parcel.readParcelableArray(null, + AutofillId.class); + final Match[] detectedMatches = (detectedFieldIds != null) + ? parcel.readParcelableArray(null, Match.class) + : null; selection.addEvent(new Event(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds, - detectedRemoteId, detectedFieldScore)); + detectedFieldIds, detectedMatches)); } return selection; } diff --git a/core/java/android/service/autofill/InternalScorer.java b/core/java/android/service/autofill/InternalScorer.java new file mode 100644 index 000000000000..0da5afc2331d --- /dev/null +++ b/core/java/android/service/autofill/InternalScorer.java @@ -0,0 +1,40 @@ +/* + * 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.service.autofill; + +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.os.Parcelable; +import android.view.autofill.AutofillValue; + +/** + * Superclass of all scorer the system understands. As this is not public all + * subclasses have to implement {@link Scorer} again. + * + * @hide + */ +@TestApi +public abstract class InternalScorer implements Scorer, Parcelable { + + /** + * Returns the classification score between an actual {@link AutofillValue} filled + * by the user and the expected value predicted by an autofill service. + * + * <p>A full-match is {@code 1.0} (representing 100%), a full mismatch is {@code 0.0} and + * partial mathces are something in between, typically using edit-distance algorithms. + */ + public abstract float getScore(@NonNull AutofillValue actualValue, @NonNull String userData); +} diff --git a/core/java/android/service/autofill/Scorer.java b/core/java/android/service/autofill/Scorer.java new file mode 100644 index 000000000000..f6a802a33e14 --- /dev/null +++ b/core/java/android/service/autofill/Scorer.java @@ -0,0 +1,35 @@ +/* + * 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.service.autofill; + +import android.annotation.TestApi; + +/** + * Helper class used to calculate a score. + * + * <p>Typically used to calculate the field classification score between an actual + * {@link android.view.autofill.AutofillValue} filled by the user and the expected value predicted + * by an autofill service. + * + * TODO(b/67867469): + * - improve javadoc + * - unhide / remove testApi + * @hide + */ +@TestApi +public interface Scorer { + +} diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java index 16d8d4ad3d86..0d378153aa0d 100644 --- a/core/java/android/service/autofill/UserData.java +++ b/core/java/android/service/autofill/UserData.java @@ -29,7 +29,6 @@ import android.content.ContentResolver; import android.os.Parcel; import android.os.Parcelable; import android.provider.Settings; -import android.util.ArraySet; import android.util.Log; import android.view.autofill.Helper; @@ -57,10 +56,12 @@ public final class UserData implements Parcelable { private static final int DEFAULT_MIN_VALUE_LENGTH = 5; private static final int DEFAULT_MAX_VALUE_LENGTH = 100; + private final InternalScorer mScorer; private final String[] mRemoteIds; private final String[] mValues; private UserData(Builder builder) { + mScorer = builder.mScorer; mRemoteIds = new String[builder.mRemoteIds.size()]; builder.mRemoteIds.toArray(mRemoteIds); mValues = new String[builder.mValues.size()]; @@ -68,6 +69,11 @@ public final class UserData implements Parcelable { } /** @hide */ + public InternalScorer getScorer() { + return mScorer; + } + + /** @hide */ public String[] getRemoteIds() { return mRemoteIds; } @@ -79,10 +85,17 @@ public final class UserData implements Parcelable { /** @hide */ public void dump(String prefix, PrintWriter pw) { - // Cannot disclose remote ids because they could contain PII + pw.print(prefix); pw.print("Scorer: "); pw.println(mScorer); + // Cannot disclose remote ids or values because they could contain PII pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length); + for (int i = 0; i < mRemoteIds.length; i++) { + pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": "); + pw.println(Helper.getRedacted(mRemoteIds[i])); + } + pw.print(prefix); pw.print("Values size: "); pw.println(mValues.length); for (int i = 0; i < mValues.length; i++) { - pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": "); pw.println(mValues[i]); + pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": "); + pw.println(Helper.getRedacted(mValues[i])); } } @@ -104,7 +117,8 @@ public final class UserData implements Parcelable { */ @TestApi public static final class Builder { - private final ArraySet<String> mRemoteIds; + private final InternalScorer mScorer; + private final ArrayList<String> mRemoteIds; private final ArrayList<String> mValues; private boolean mDestroyed; @@ -112,15 +126,23 @@ public final class UserData implements Parcelable { * Creates a new builder for the user data used for <a href="#FieldsClassification">fields * classification</a>. * - * @throws IllegalArgumentException if {@code remoteId} or {@code value} are empty or if the - * length of {@code value} is lower than {@link UserData#getMinValueLength()} - * or higher than {@link UserData#getMaxValueLength()}. + * @throws IllegalArgumentException if any of the following occurs: + * <ol> + * <li>{@code remoteId} is empty + * <li>{@code value} is empty + * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()} + * <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()} + * <li>{@code scorer} is not instance of a class provided by the Android System. + * </ol> */ - public Builder(@NonNull String remoteId, @NonNull String value) { + public Builder(@NonNull Scorer scorer, @NonNull String remoteId, @NonNull String value) { + Preconditions.checkArgument((scorer instanceof InternalScorer), + "not provided by Android System: " + scorer); + mScorer = (InternalScorer) scorer; checkValidRemoteId(remoteId); checkValidValue(value); final int capacity = getMaxUserDataSize(); - mRemoteIds = new ArraySet<>(capacity); + mRemoteIds = new ArrayList<>(capacity); mValues = new ArrayList<>(capacity); mRemoteIds.add(remoteId); mValues.add(value); @@ -149,10 +171,14 @@ public final class UserData implements Parcelable { Preconditions.checkState(!mRemoteIds.contains(remoteId), // Don't include remoteId on message because it could contain PII "already has entry with same remoteId"); + Preconditions.checkState(!mValues.contains(value), + // Don't include remoteId on message because it could contain PII + "already has entry with same value"); Preconditions.checkState(mRemoteIds.size() < getMaxUserDataSize(), "already added " + mRemoteIds.size() + " elements"); mRemoteIds.add(remoteId); mValues.add(value); + return this; } @@ -197,8 +223,9 @@ public final class UserData implements Parcelable { public String toString() { if (!sDebug) return super.toString(); - // Cannot disclose keys or values because they could contain PII - final StringBuilder builder = new StringBuilder("UserData: [remoteIds="); + final StringBuilder builder = new StringBuilder("UserData: [scorer=").append(mScorer); + // Cannot disclose remote ids or values because they could contain PII + builder.append(", remoteIds="); Helper.appendRedacted(builder, mRemoteIds); builder.append(", values="); Helper.appendRedacted(builder, mValues); @@ -216,6 +243,7 @@ public final class UserData implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mScorer, flags); parcel.writeStringArray(mRemoteIds); parcel.writeStringArray(mValues); } @@ -227,9 +255,10 @@ public final class UserData implements Parcelable { // Always go through the builder to ensure the data ingested by // the system obeys the contract of the builder to avoid attacks // using specially crafted parcels. + final InternalScorer scorer = parcel.readParcelable(null); final String[] remoteIds = parcel.readStringArray(); final String[] values = parcel.readStringArray(); - final Builder builder = new Builder(remoteIds[0], values[0]); + final Builder builder = new Builder(scorer, remoteIds[0], values[0]); for (int i = 1; i < remoteIds.length; i++) { builder.add(remoteIds[i], values[i]); } @@ -259,14 +288,14 @@ public final class UserData implements Parcelable { } /** - * Gets the minimum length of values passed to {@link Builder#Builder(String, String)}. + * Gets the minimum length of values passed to {@link Builder#Builder(Scorer, String, String)}. */ public static int getMinValueLength() { return getInt(AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, DEFAULT_MIN_VALUE_LENGTH); } /** - * Gets the maximum length of values passed to {@link Builder#Builder(String, String)}. + * Gets the maximum length of values passed to {@link Builder#Builder(Scorer, String, String)}. */ public static int getMaxValueLength() { return getInt(AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, DEFAULT_MAX_VALUE_LENGTH); diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 512f2df9747e..f658ae03c927 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -46,6 +46,7 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; @@ -65,11 +66,13 @@ public class ZenModeConfig implements Parcelable { public static final int MAX_SOURCE = SOURCE_STAR; private static final int DEFAULT_SOURCE = SOURCE_CONTACT; + public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE"; + public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE"; + public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID, + EVENTS_DEFAULT_RULE_ID); + public static final int[] ALL_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY }; - public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, - Calendar.WEDNESDAY, Calendar.THURSDAY }; - public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY }; public static final int[] MINUTE_BUCKETS = generateMinuteBuckets(); private static final int SECONDS_MS = 1000; @@ -530,6 +533,13 @@ public class ZenModeConfig implements Parcelable { rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0); rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER); rt.condition = readConditionXml(parser); + + // all default rules and user created rules updated to zenMode important interruptions + if (rt.zenMode != Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS + && Condition.isValidId(rt.conditionId, SYSTEM_AUTHORITY)) { + Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name); + rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + } return rt; } diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java index d50395e223e5..0a00794a1471 100644 --- a/core/java/android/util/KeyValueListParser.java +++ b/core/java/android/util/KeyValueListParser.java @@ -149,6 +149,34 @@ public class KeyValueListParser { } /** + * Get the value for key as an integer array. + * + * The value should be encoded as "0:1:2:3:4" + * + * @param key The key to lookup. + * @param def The value to return if the key was not found. + * @return the int[] value associated with the key. + */ + public int[] getIntArray(String key, int[] def) { + String value = mValues.get(key); + if (value != null) { + try { + String[] parts = value.split(":"); + if (parts.length > 0) { + int[] ret = new int[parts.length]; + for (int i = 0; i < parts.length; i++) { + ret[i] = Integer.parseInt(parts[i]); + } + return ret; + } + } catch (NumberFormatException e) { + // fallthrough + } + } + return def; + } + + /** * @return the number of keys. */ public int size() { diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 2ffa1c5eb4c0..ba6b6cf6e106 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -164,6 +164,7 @@ public final class Choreographer { private long mLastFrameTimeNanos; private long mFrameIntervalNanos; private boolean mDebugPrintNextFrameTimeDelta; + private int mFPSDivisor = 1; /** * Contains information about the current frame for jank-tracking, @@ -601,6 +602,11 @@ public final class Choreographer { } } + void setFPSDivisor(int divisor) { + if (divisor <= 0) divisor = 1; + mFPSDivisor = divisor; + } + void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { @@ -643,6 +649,14 @@ public final class Choreographer { return; } + if (mFPSDivisor > 1) { + long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos; + if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { + scheduleVsyncLocked(); + return; + } + } + mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 29032a7bbc73..9e103a38263c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -147,7 +147,6 @@ interface IWindowManager void exitKeyguardSecurely(IOnKeyguardExitResult callback); boolean isKeyguardLocked(); boolean isKeyguardSecure(); - boolean inKeyguardRestrictedInputMode(); void dismissKeyguard(IKeyguardDismissCallback callback); // Requires INTERACT_ACROSS_USERS_FULL permission diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 7c76bab2343d..0a69772c3606 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -190,6 +190,17 @@ public final class ThreadedRenderer { public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY = "debug.hwui.show_non_rect_clip"; + /** + * Sets the FPS devisor to lower the FPS. + * + * Sets a positive integer as a divisor. 1 (the default value) menas the full FPS, and 2 + * means half the full FPS. + * + * + * @hide + */ + public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor"; + static { // Try to check OpenGL support early if possible. isAvailable(); @@ -955,6 +966,9 @@ public final class ThreadedRenderer { if (mInitialized) return; mInitialized = true; mAppContext = context.getApplicationContext(); + + // b/68769804: For low FPS experiments. + setFPSDivisor(SystemProperties.getInt(DEBUG_FPS_DIVISOR, 1)); initSched(renderProxy); initGraphicsStats(); } @@ -1007,6 +1021,13 @@ public final class ThreadedRenderer { observer.mNative = null; } + /** b/68769804: For low FPS experiments. */ + public static void setFPSDivisor(int divisor) { + if (divisor <= 0) divisor = 1; + Choreographer.getInstance().setFPSDivisor(divisor); + nHackySetRTAnimationsEnabled(divisor == 1); + } + /** Not actually public - internal use only. This doc to make lint happy */ public static native void disableVsync(); @@ -1075,4 +1096,6 @@ public final class ThreadedRenderer { private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height); private static native void nSetHighContrastText(boolean enabled); + // For temporary experimentation b/66945974 + private static native void nHackySetRTAnimationsEnabled(boolean enabled); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0525ab164b02..9cfae8fb4745 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -893,6 +893,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sAutoFocusableOffUIThreadWontNotifyParents; + /** + * Prior to P things like setScaleX() allowed passing float values that were bogus such as + * Float.NaN. If the app is targetting P or later then passing these values will result in an + * exception being thrown. If the app is targetting an earlier SDK version, then we will + * silently clamp these values to avoid crashes elsewhere when the rendering code hits + * these bogus values. + */ + private static boolean sThrowOnInvalidFloatProperties; + /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @@ -4752,6 +4761,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sUseDefaultFocusHighlight = context.getResources().getBoolean( com.android.internal.R.bool.config_useDefaultFocusHighlight); + sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; + sCompatibilityDone = true; } } @@ -7208,8 +7219,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param text The announcement text. */ public void announceForAccessibility(CharSequence text) { - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_ANNOUNCEMENT) && mParent != null) { + if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_ANNOUNCEMENT); onInitializeAccessibilityEvent(event); @@ -10968,8 +10978,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; invalidate(); - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); event.setAction(action); @@ -11794,8 +11803,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex) { - if (mParent == null || !AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY)) { + if (mParent == null) { return; } AccessibilityEvent event = AccessibilityEvent.obtain( @@ -14275,7 +14283,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setScaleX(float scaleX) { if (scaleX != getScaleX()) { - requireIsFinite(scaleX, "scaleX"); + scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); invalidateViewProperty(true, false); mRenderNode.setScaleX(scaleX); invalidateViewProperty(false, true); @@ -14312,7 +14320,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setScaleY(float scaleY) { if (scaleY != getScaleY()) { - requireIsFinite(scaleY, "scaleY"); + scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); invalidateViewProperty(true, false); mRenderNode.setScaleY(scaleY); invalidateViewProperty(false, true); @@ -14862,13 +14870,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - private static void requireIsFinite(float transform, String propertyName) { - if (Float.isNaN(transform)) { - throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN"); + private static float sanitizeFloatPropertyValue(float value, String propertyName) { + return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); + } + + private static float sanitizeFloatPropertyValue(float value, String propertyName, + float min, float max) { + // The expected "nothing bad happened" path + if (value >= min && value <= max) return value; + + if (value < min || value == Float.NEGATIVE_INFINITY) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + + value + ", the value must be >= " + min); + } + return min; } - if (Float.isInfinite(transform)) { - throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity"); + + if (value > max || value == Float.POSITIVE_INFINITY) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " + + value + ", the value must be <= " + max); + } + return max; } + + if (Float.isNaN(value)) { + if (sThrowOnInvalidFloatProperties) { + throw new IllegalArgumentException( + "Cannot set '" + propertyName + "' to Float.NaN"); + } + return 0; // Unclear which direction this NaN went so... 0? + } + + // Shouldn't be possible to reach this. + throw new IllegalStateException("How do you get here?? " + value); } /** @@ -14957,7 +14993,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setElevation(float elevation) { if (elevation != getElevation()) { - requireIsFinite(elevation, "elevation"); + elevation = sanitizeFloatPropertyValue(elevation, "elevation"); invalidateViewProperty(true, false); mRenderNode.setElevation(elevation); invalidateViewProperty(false, true); @@ -15050,7 +15086,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public void setTranslationZ(float translationZ) { if (translationZ != getTranslationZ()) { - requireIsFinite(translationZ, "translationZ"); + translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); invalidateViewProperty(true, false); mRenderNode.setTranslationZ(translationZ); invalidateViewProperty(false, true); @@ -26185,8 +26221,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @Override public void run() { - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_SCROLLED)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_SCROLLED); event.setScrollDeltaX(mDeltaX); diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 0375635fd708..35f6acba04dc 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -24,7 +24,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemService; -import android.annotation.TestApi; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -188,7 +187,6 @@ public final class AccessibilityManager { * * @hide */ - @TestApi public interface AccessibilityServicesStateChangeListener { /** @@ -454,18 +452,6 @@ public final class AccessibilityManager { } /** - * Returns whether there are observers registered for this event type. If - * this method returns false you shuold not generate events of this type - * to conserve resources. - * - * @param type The event type. - * @return Whether the event is being observed. - */ - public boolean isObservedEventType(@AccessibilityEvent.EventType int type) { - return mIsEnabled && (mRelevantEventTypes & type) != 0; - } - - /** * Requests feedback interruption from all accessibility services. */ public void interrupt() { @@ -697,7 +683,6 @@ public final class AccessibilityManager { * for a callback on the process's main handler. * @hide */ - @TestApi public void addAccessibilityServicesStateChangeListener( @NonNull AccessibilityServicesStateChangeListener listener, @Nullable Handler handler) { synchronized (mLock) { @@ -713,7 +698,6 @@ public final class AccessibilityManager { * * @hide */ - @TestApi public void removeAccessibilityServicesStateChangeListener( @NonNull AccessibilityServicesStateChangeListener listener) { // Final CopyOnWriteArrayList - no lock needed. diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 9a99e5398c8e..4c47b8922b66 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1057,6 +1057,23 @@ public final class AutofillManager { } /** + * TODO(b/67867469): + * - proper javadoc + * - mention this method in other places + * - unhide / remove testApi + * @hide + */ + @TestApi + public boolean isFieldClassificationEnabled() { + try { + return mService.isFieldClassificationEnabled(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } + + /** * Returns {@code true} if autofill is supported by the current device and * is supported for this user. * diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java index b95704af7d44..4b2c53c7eb84 100644 --- a/core/java/android/view/autofill/Helper.java +++ b/core/java/android/view/autofill/Helper.java @@ -18,11 +18,6 @@ package android.view.autofill; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Bundle; - -import java.util.Arrays; -import java.util.Objects; -import java.util.Set; /** @hide */ public final class Helper { @@ -31,37 +26,20 @@ public final class Helper { public static boolean sDebug = false; public static boolean sVerbose = false; - public static final String REDACTED = "[REDACTED]"; - - static StringBuilder append(StringBuilder builder, Bundle bundle) { - if (bundle == null || !sDebug) { - builder.append("N/A"); - } else if (!sVerbose) { - builder.append(REDACTED); - } else { - final Set<String> keySet = bundle.keySet(); - builder.append("[Bundle with ").append(keySet.size()).append(" extras:"); - for (String key : keySet) { - final Object value = bundle.get(key); - builder.append(' ').append(key).append('='); - builder.append((value instanceof Object[]) - ? Arrays.toString((Objects[]) value) : value); - } - builder.append(']'); - } - return builder; - } - /** * Appends {@code value} to the {@code builder} redacting its contents. */ public static void appendRedacted(@NonNull StringBuilder builder, @Nullable CharSequence value) { - if (value == null) { - builder.append("null"); - } else { - builder.append(value.length()).append("_chars"); - } + builder.append(getRedacted(value)); + } + + /** + * Gets the redacted version of a value. + */ + @NonNull + public static String getRedacted(@Nullable CharSequence value) { + return (value == null) ? "null" : value.length() + "_chars"; } /** diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 7d6a19f529ce..f49aa5b4d442 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -56,4 +56,5 @@ interface IAutoFillManager { void onPendingSaveUi(int operation, IBinder token); UserData getUserData(); void setUserData(in UserData userData); + boolean isFieldClassificationEnabled(); } diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index b37928066899..4d3189efa64e 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -1952,8 +1952,7 @@ public class NumberPicker extends LinearLayout { CharSequence beforeText = mInputText.getText(); if (!text.equals(beforeText.toString())) { mInputText.setText(text); - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); mInputText.onInitializeAccessibilityEvent(event); @@ -2613,7 +2612,7 @@ public class NumberPicker extends LinearLayout { } private void sendAccessibilityEventForVirtualText(int eventType) { - if (AccessibilityManager.getInstance(mContext).isObservedEventType(eventType)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); mInputText.onInitializeAccessibilityEvent(event); mInputText.onPopulateAccessibilityEvent(event); @@ -2624,7 +2623,7 @@ public class NumberPicker extends LinearLayout { private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType, String text) { - if (AccessibilityManager.getInstance(mContext).isObservedEventType(eventType)) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setClassName(Button.class.getName()); event.setPackageName(mContext.getPackageName()); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 71532a72d7b4..d9bc51fffd6a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10836,10 +10836,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, int fromIndex, int removedCount, int addedCount) { - if (!AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)) { - return; - } AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); event.setFromIndex(fromIndex); diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index bfde6ac38e55..d80712006a53 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -504,8 +504,7 @@ public class Toast { private void trySendAccessibilityEvent() { AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mView.getContext()); - if (!accessibilityManager.isObservedEventType( - AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)) { + if (!accessibilityManager.isEnabled()) { return; } // treat toasts as notifications since they are used to diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 55c582ed47b4..293471c686e5 100644 --- a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Google Inc. + * Copyright 2017 Google Inc. * * 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 @@ -14,7 +14,7 @@ * the License. */ -package com.android.server.policy; +package com.android.internal.accessibility; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; @@ -35,6 +35,7 @@ import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Slog; import android.view.Window; import android.view.WindowManager; @@ -43,20 +44,30 @@ import android.view.accessibility.AccessibilityManager; import android.widget.Toast; import com.android.internal.R; -import java.util.List; +import java.util.Collections; +import java.util.Map; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static com.android.internal.util.ArrayUtils.convertToLongArray; + /** * Class to help manage the accessibility shortcut */ public class AccessibilityShortcutController { private static final String TAG = "AccessibilityShortcutController"; + + // Dummy component names for framework features + public static final ComponentName COLOR_INVERSION_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "ColorInversion"); + public static final ComponentName DALTONIZER_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "Daltonizer"); + private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY) .build(); - + private static Map<ComponentName, ToggleableFrameworkFeatureInfo> sFrameworkShortcutFeaturesMap; private final Context mContext; private AlertDialog mAlertDialog; @@ -67,6 +78,15 @@ public class AccessibilityShortcutController { // Visible for testing public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider(); + /** + * Get the component name string for the service or feature currently assigned to the + * accessiblity shortcut + * + * @param context A valid context + * @param userId The user ID of interest + * @return The flattened component name string of the service selected by the user, or the + * string for the default service if the user has not made a selection + */ public static String getTargetServiceComponentNameString( Context context, int userId) { final String currentShortcutServiceId = Settings.Secure.getStringForUser( @@ -78,6 +98,29 @@ public class AccessibilityShortcutController { return context.getString(R.string.config_defaultAccessibilityService); } + /** + * @return An immutable map from dummy component names to feature info for toggling a framework + * feature + */ + public static Map<ComponentName, ToggleableFrameworkFeatureInfo> + getFrameworkShortcutFeaturesMap() { + if (sFrameworkShortcutFeaturesMap == null) { + Map<ComponentName, ToggleableFrameworkFeatureInfo> featuresMap = new ArrayMap<>(2); + featuresMap.put(COLOR_INVERSION_COMPONENT_NAME, + new ToggleableFrameworkFeatureInfo( + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, + "1" /* Value to enable */, "0" /* Value to disable */, + R.string.color_inversion_feature_name)); + featuresMap.put(DALTONIZER_COMPONENT_NAME, + new ToggleableFrameworkFeatureInfo( + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, + "1" /* Value to enable */, "0" /* Value to disable */, + R.string.color_correction_feature_name)); + sFrameworkShortcutFeaturesMap = Collections.unmodifiableMap(featuresMap); + } + return sFrameworkShortcutFeaturesMap; + } + public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) { mContext = context; mUserId = initialUserId; @@ -160,8 +203,8 @@ public class AccessibilityShortcutController { if ((vibrator != null) && vibrator.hasVibrator()) { // Don't check if haptics are disabled, as we need to alert the user that their // way of interacting with the phone may change if they activate the shortcut - long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(), - R.array.config_longPressVibePattern); + long[] vibePattern = convertToLongArray( + mContext.getResources().getIntArray(R.array.config_longPressVibePattern)); vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES); } @@ -187,22 +230,24 @@ public class AccessibilityShortcutController { } // Show a toast alerting the user to what's happening - final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); - if (serviceInfo == null) { + final String serviceName = getShortcutFeatureDescription(false /* no summary */); + if (serviceName == null) { Slog.e(TAG, "Accessibility shortcut set to invalid service"); return; } - String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo) - ? R.string.accessibility_shortcut_disabling_service - : R.string.accessibility_shortcut_enabling_service); - String toastMessage = String.format(toastMessageFormatString, - serviceInfo.getResolveInfo() - .loadLabel(mContext.getPackageManager()).toString()); - Toast warningToast = mFrameworkObjectProvider.makeToastFromText( - mContext, toastMessage, Toast.LENGTH_LONG); - warningToast.getWindowParams().privateFlags |= - WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; - warningToast.show(); + // For accessibility services, show a toast explaining what we're doing. + final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); + if (serviceInfo != null) { + String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo) + ? R.string.accessibility_shortcut_disabling_service + : R.string.accessibility_shortcut_enabling_service); + String toastMessage = String.format(toastMessageFormatString, serviceName); + Toast warningToast = mFrameworkObjectProvider.makeToastFromText( + mContext, toastMessage, Toast.LENGTH_LONG); + warningToast.getWindowParams().privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + warningToast.show(); + } mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext) .performAccessibilityShortcut(); @@ -210,18 +255,18 @@ public class AccessibilityShortcutController { } private AlertDialog createShortcutWarningDialog(int userId) { - final AccessibilityServiceInfo serviceInfo = getInfoForTargetService(); + final String serviceDescription = getShortcutFeatureDescription(true /* Include summary */); - if (serviceInfo == null) { + if (serviceDescription == null) { return null; } final String warningMessage = String.format( mContext.getString(R.string.accessibility_shortcut_toogle_warning), - serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString()); + serviceDescription); final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder( // Use SystemUI context so we pick up any theme set in a vendor overlay - ActivityThread.currentActivityThread().getSystemUiContext()) + mFrameworkObjectProvider.getSystemUiContext()) .setTitle(R.string.accessibility_shortcut_warning_dialog_title) .setMessage(warningMessage) .setCancelable(false) @@ -253,6 +298,34 @@ public class AccessibilityShortcutController { ComponentName.unflattenFromString(currentShortcutServiceString)); } + private String getShortcutFeatureDescription(boolean includeSummary) { + final String currentShortcutServiceString = getTargetServiceComponentNameString( + mContext, UserHandle.USER_CURRENT); + if (currentShortcutServiceString == null) { + return null; + } + final ComponentName targetComponentName = + ComponentName.unflattenFromString(currentShortcutServiceString); + final ToggleableFrameworkFeatureInfo frameworkFeatureInfo = + getFrameworkShortcutFeaturesMap().get(targetComponentName); + if (frameworkFeatureInfo != null) { + return frameworkFeatureInfo.getLabel(mContext); + } + final AccessibilityServiceInfo serviceInfo = mFrameworkObjectProvider + .getAccessibilityManagerInstance(mContext).getInstalledServiceInfoWithComponentName( + targetComponentName); + if (serviceInfo == null) { + return null; + } + final PackageManager pm = mContext.getPackageManager(); + String label = serviceInfo.getResolveInfo().loadLabel(pm).toString(); + String summary = serviceInfo.loadSummary(pm).toString(); + if (!includeSummary || TextUtils.isEmpty(summary)) { + return label; + } + return String.format("%s\n%s", label, summary); + } + private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) { AccessibilityManager accessibilityManager = mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext); @@ -264,6 +337,51 @@ public class AccessibilityShortcutController { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } + /** + * Immutable class to hold info about framework features that can be controlled by shortcut + */ + public static class ToggleableFrameworkFeatureInfo { + private final String mSettingKey; + private final String mSettingOnValue; + private final String mSettingOffValue; + private final int mLabelStringResourceId; + // These go to the settings wrapper + private int mIconDrawableId; + + ToggleableFrameworkFeatureInfo(String settingKey, String settingOnValue, + String settingOffValue, int labelStringResourceId) { + mSettingKey = settingKey; + mSettingOnValue = settingOnValue; + mSettingOffValue = settingOffValue; + mLabelStringResourceId = labelStringResourceId; + } + + /** + * @return The settings key to toggle between two values + */ + public String getSettingKey() { + return mSettingKey; + } + + /** + * @return The value to write to settings to turn the feature on + */ + public String getSettingOnValue() { + return mSettingOnValue; + } + + /** + * @return The value to write to settings to turn the feature off + */ + public String getSettingOffValue() { + return mSettingOffValue; + } + + public String getLabel(Context context) { + return context.getString(mLabelStringResourceId); + } + } + // Class to allow mocking of static framework calls public static class FrameworkObjectProvider { public AccessibilityManager getAccessibilityManagerInstance(Context context) { @@ -277,5 +395,9 @@ public class AccessibilityShortcutController { public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) { return Toast.makeText(context, charSequence, duration); } + + public Context getSystemUiContext() { + return ActivityThread.currentActivityThread().getSystemUiContext(); + } } } diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags index 93d5a0373d2d..a440ee402294 100644 --- a/core/java/com/android/internal/logging/EventLogTags.logtags +++ b/core/java/com/android/internal/logging/EventLogTags.logtags @@ -8,3 +8,8 @@ option java_package com.android.internal.logging; 524292 sysui_multi_action (content|4) 524290 sysui_count (name|3),(increment|1) 524291 sysui_histogram (name|3),(bucket|1) + +# --------------------------- +# LatencyTracker.java +# --------------------------- +36070 sysui_latency (action|1|6),(latency|1|3) diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java index cffba0177d14..7558f8cee233 100644 --- a/core/java/com/android/internal/os/BackgroundThread.java +++ b/core/java/com/android/internal/os/BackgroundThread.java @@ -35,7 +35,7 @@ public final class BackgroundThread extends HandlerThread { if (sInstance == null) { sInstance = new BackgroundThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); + sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 9336ddd05c28..aa8566885aff 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -292,6 +292,15 @@ public class ArrayUtils { return array; } + public static @Nullable long[] convertToLongArray(@Nullable int[] intArray) { + if (intArray == null) return null; + long[] array = new long[intArray.length]; + for (int i = 0; i < intArray.length; i++) { + array[i] = (long) intArray[i]; + } + return array; + } + /** * Adds value to given array if not already present, providing set-like * behavior. diff --git a/packages/SystemUI/src/com/android/keyguard/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index cee0afcd37d6..72cd24888dcc 100644 --- a/packages/SystemUI/src/com/android/keyguard/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -1,20 +1,18 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * 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 + * 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 + * 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.keyguard; +package com.android.internal.util; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,7 +26,7 @@ import android.util.EventLog; import android.util.Log; import android.util.SparseLongArray; -import com.android.systemui.EventLogTags; +import com.android.internal.logging.EventLogTags; /** * Class to track various latencies in SystemUI. It then outputs the latency to logcat so these @@ -76,13 +74,19 @@ public class LatencyTracker { */ public static final int ACTION_TURN_ON_SCREEN = 5; + /** + * Time it takes to rotate the screen. + */ + public static final int ACTION_ROTATE_SCREEN = 6; + private static final String[] NAMES = new String[] { "expand panel", "toggle recents", "fingerprint wake-and-unlock", "check credential", "check credential unlocked", - "turn on screen" }; + "turn on screen", + "rotate the screen"}; private static LatencyTracker sLatencyTracker; diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java index 759a41a2c0ca..50ad547e6e65 100644 --- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java +++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java @@ -186,9 +186,6 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { } final AccessibilityEvent event = createEvent(virtualViewId, eventType); - if (event == null) { - return false; - } return parent.requestSendAccessibilityEvent(mView, event); } @@ -243,9 +240,6 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { if (parent != null) { final AccessibilityEvent event = createEvent(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - if (event == null) { - return; - } event.setContentChangeTypes(changeTypes); parent.requestSendAccessibilityEvent(mView, event); } @@ -311,9 +305,6 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { * the specified item. */ private AccessibilityEvent createEventForHost(int eventType) { - if (!AccessibilityManager.getInstance(mContext).isObservedEventType(eventType)) { - return null; - } final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); mView.onInitializeAccessibilityEvent(event); @@ -334,9 +325,6 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { * the specified item. */ private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) { - if (!AccessibilityManager.getInstance(mContext).isObservedEventType(eventType)) { - return null; - } final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setEnabled(true); event.setClassName(DEFAULT_CLASS_NAME); diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 71742cbbb180..0a90b97d55ef 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -124,7 +124,7 @@ static jobject android_view_InputChannel_createInputChannel(JNIEnv* env, static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env, jclass clazz, jstring nameObj) { const char* nameChars = env->GetStringUTFChars(nameObj, NULL); - String8 name(nameChars); + std::string name = nameChars; env->ReleaseStringUTFChars(nameObj, nameChars); sp<InputChannel> serverChannel; @@ -166,7 +166,7 @@ static void android_view_InputChannel_nativeDispose(JNIEnv* env, jobject obj, jb if (nativeInputChannel) { if (finalized) { ALOGW("Input channel object '%s' was finalized without being disposed!", - nativeInputChannel->getInputChannel()->getName().string()); + nativeInputChannel->getInputChannel()->getName().c_str()); } nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj); @@ -212,7 +212,7 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject return; } - InputChannel* inputChannel = new InputChannel(name, dupFd); + InputChannel* inputChannel = new InputChannel(name.string(), dupFd); NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel); android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel); @@ -230,7 +230,7 @@ static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject o sp<InputChannel> inputChannel = nativeInputChannel->getInputChannel(); parcel->writeInt32(1); - parcel->writeString8(inputChannel->getName()); + parcel->writeString8(String8(inputChannel->getName().c_str())); parcel->writeDupFileDescriptor(inputChannel->getFd()); } else { parcel->writeInt32(0); @@ -245,7 +245,7 @@ static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj) return NULL; } - jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().string()); + jstring name = env->NewStringUTF(nativeInputChannel->getInputChannel()->getName().c_str()); return name; } diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index c457ab0cdb04..52c84a4f2cc6 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -79,7 +79,7 @@ private: void setFdEvents(int events); const char* getInputChannelName() { - return mInputConsumer.getChannel()->getName().string(); + return mInputConsumer.getChannel()->getName().c_str(); } virtual int handleEvent(int receiveFd, int events, void* data); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 58ccef183f96..f87abacc3aff 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -71,7 +71,7 @@ private: uint32_t mNextPublishedSeq; const char* getInputChannelName() { - return mInputPublisher.getChannel()->getName().string(); + return mInputPublisher.getChannel()->getName().c_str(); } virtual int handleEvent(int receiveFd, int events, void* data); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 519a8858aa03..9f3475abe564 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -937,6 +937,11 @@ static void android_view_ThreadedRenderer_setHighContrastText(JNIEnv*, jclass, j Properties::enableHighContrastText = enable; } +static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass, + jboolean enable) { + Properties::enableRTAnimations = enable; +} + // ---------------------------------------------------------------------------- // FrameMetricsObserver // ---------------------------------------------------------------------------- @@ -1041,6 +1046,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode }, { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync }, { "nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText }, + { "nHackySetRTAnimationsEnabled", "(Z)V", + (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled }, }; static JavaVM* mJvm = nullptr; diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index faf3c2f1ec22..51ffa6007ae0 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7571,6 +7571,15 @@ <flag name="keyguard" value="0x2" /> <flag name="searchbox" value="0x4" /> </attr> + <!-- Flags indicating various features supported by the widget. These are hints to the + widget host, and do not actually change the behavior of the widget. --> + <attr name="widgetFeatures" format="integer"> + <!-- The widget can be reconfigured anytime after it is bound --> + <flag name="reconfigurable" value="0x1" /> + <!-- The widget is added directly by the app, and does not need to appear in + the global list of available widgets --> + <flag name="hide_from_picker" value="0x2" /> + </attr> </declare-styleable> <!-- =============================== --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d79df353f7c7..373a65664695 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2858,6 +2858,7 @@ <public name="versionMajor" /> <!-- @hide @SystemApi --> <public name="isVrOnly"/> + <public name="widgetFeatures" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8958af4bffc8..ef8f6afc5313 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4034,6 +4034,14 @@ shortcut enabled.--> <string name="leave_accessibility_shortcut_on">Use Shortcut</string> + <!-- Title of Color Inversion feature shown in the warning dialog about the accessibility + shortcut. --> + <string name="color_inversion_feature_name">Color Inversion</string> + + <!-- Title of Color Correction feature, which is mostly used to help users who are colorblind, + shown in the warning dialog about the accessibility shortcut. --> + <string name="color_correction_feature_name">Color Correction</string> + <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service.--> <string name="accessibility_shortcut_enabling_service">Accessibility Shortcut turned @@ -4466,6 +4474,9 @@ <!-- Zen mode - name of default automatic calendar event-based rule. [CHAR LIMIT=40] --> <string name="zen_mode_default_events_name">Event</string> + <!-- Zen mode - name of default automatic calendar time-based rule that is triggered every night (when sleeping). [CHAR LIMIT=40] --> + <string name="zen_mode_default_every_night_name">Sleeping</string> + <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] --> <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index cbd34f9e1520..6da24bd2657b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1067,6 +1067,8 @@ <java-symbol type="string" name="action_bar_home_description_format" /> <java-symbol type="string" name="action_bar_home_subtitle_description_format" /> <java-symbol type="string" name="wireless_display_route_description" /> + <java-symbol type="string" name="user_owner_label" /> + <java-symbol type="string" name="managed_profile_label" /> <java-symbol type="string" name="managed_profile_label_badge" /> <java-symbol type="string" name="managed_profile_label_badge_2" /> <java-symbol type="string" name="managed_profile_label_badge_3" /> @@ -2262,6 +2264,7 @@ <java-symbol type="string" name="zen_mode_default_weeknights_name" /> <java-symbol type="string" name="zen_mode_default_weekends_name" /> <java-symbol type="string" name="zen_mode_default_events_name" /> + <java-symbol type="string" name="zen_mode_default_every_night_name" /> <java-symbol type="array" name="config_system_condition_providers" /> <java-symbol type="string" name="muted_by" /> <java-symbol type="string" name="zen_mode_alarm" /> @@ -2911,6 +2914,8 @@ <java-symbol type="string" name="accessibility_shortcut_disabling_service" /> <java-symbol type="string" name="disable_accessibility_shortcut" /> <java-symbol type="string" name="leave_accessibility_shortcut_on" /> + <java-symbol type="string" name="color_inversion_feature_name" /> + <java-symbol type="string" name="color_correction_feature_name" /> <java-symbol type="string" name="config_defaultAccessibilityService" /> <!-- Accessibility Button --> diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk index c409e3af7fa7..8df3827935aa 100644 --- a/core/tests/BroadcastRadioTests/Android.mk +++ b/core/tests/BroadcastRadioTests/Android.mk @@ -26,6 +26,8 @@ LOCAL_MODULE_TAGS := tests LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng +LOCAL_JAVA_LIBRARIES := android.test.base + LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index f2eb872893b4..47990a168ab3 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -30,6 +30,7 @@ LOCAL_DX_FLAGS := --core-library LOCAL_JACK_FLAGS := --multi-dex native LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa LOCAL_STATIC_JAVA_LIBRARIES := \ + frameworks-base-testutils \ core-tests-support \ android-common \ frameworks-core-util-lib \ @@ -44,7 +45,14 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ truth-prebuilt \ print-test-util-lib -LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + conscrypt \ + telephony-common \ + org.apache.http.legacy \ + android.test.base \ + android.test.mock \ + LOCAL_PACKAGE_NAME := FrameworksCoreTests LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java b/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java new file mode 100644 index 000000000000..80e4c0214ad4 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/crossprofile/CrossProfileAppsTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.crossprofile; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; +import android.platform.test.annotations.Presubmit; + +import com.android.internal.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.List; + +/** + * Build/Install/Run: + * bit FrameworksCoreTests:android.content.pm.crossprofile.CrossProfileAppsTest + */ +@Presubmit +@RunWith(MockitoJUnitRunner.class) +public class CrossProfileAppsTest { + private static final UserHandle PERSONAL_PROFILE = UserHandle.of(0); + private static final UserHandle MANAGED_PROFILE = UserHandle.of(10); + private static final String MY_PACKAGE = "my.package"; + + private List<UserHandle> mTargetProfiles; + + @Mock + private Context mContext; + @Mock + private UserManager mUserManager; + @Mock + private ICrossProfileApps mService; + @Mock + private Resources mResources; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Drawable mDrawable; + private CrossProfileApps mCrossProfileApps; + + @Before + public void initCrossProfileApps() { + mCrossProfileApps = new CrossProfileApps(mContext, mService); + } + + @Before + public void mockContext() { + when(mContext.getPackageName()).thenReturn(MY_PACKAGE); + when(mContext.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + } + + @Before + public void mockResources() { + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getDrawable(anyInt(), nullable(Resources.Theme.class))) + .thenReturn(mDrawable); + } + + @Before + public void initUsers() throws Exception { + when(mUserManager.isManagedProfile(PERSONAL_PROFILE.getIdentifier())).thenReturn(false); + when(mUserManager.isManagedProfile(MANAGED_PROFILE.getIdentifier())).thenReturn(true); + + mTargetProfiles = new ArrayList<>(); + when(mService.getTargetUserProfiles(MY_PACKAGE)).thenReturn(mTargetProfiles); + } + + @Test + public void getProfileSwitchingLabel_managedProfile() { + setValidTargetProfile(MANAGED_PROFILE); + + mCrossProfileApps.getProfileSwitchingLabel(MANAGED_PROFILE); + verify(mResources).getString(R.string.managed_profile_label); + } + + @Test + public void getProfileSwitchingLabel_personalProfile() { + setValidTargetProfile(PERSONAL_PROFILE); + + mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE); + verify(mResources).getString(R.string.user_owner_label); + } + + @Test(expected = SecurityException.class) + public void getProfileSwitchingLabel_securityException() { + mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE); + } + + @Test + public void getProfileSwitchingIcon_managedProfile() { + setValidTargetProfile(MANAGED_PROFILE); + + mCrossProfileApps.getProfileSwitchingIcon(MANAGED_PROFILE); + verify(mResources).getDrawable(R.drawable.ic_corp_badge, null); + } + + @Test + public void getProfileSwitchingIcon_personalProfile() { + setValidTargetProfile(PERSONAL_PROFILE); + + mCrossProfileApps.getProfileSwitchingIcon(PERSONAL_PROFILE); + verify(mResources).getDrawable(R.drawable.ic_account_circle, null); + } + + @Test(expected = SecurityException.class) + public void getProfileSwitchingIcon_securityException() { + mCrossProfileApps.getProfileSwitchingIcon(PERSONAL_PROFILE); + } + + private void setValidTargetProfile(UserHandle userHandle) { + mTargetProfiles.add(userHandle); + } +} diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java new file mode 100644 index 000000000000..5189df574a33 --- /dev/null +++ b/core/tests/coretests/src/android/os/EnvironmentTest.java @@ -0,0 +1,103 @@ +/* + * 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.os; + +import static android.os.Environment.HAS_ANDROID; +import static android.os.Environment.HAS_DCIM; +import static android.os.Environment.HAS_DOWNLOADS; +import static android.os.Environment.HAS_OTHER; +import static android.os.Environment.classifyExternalStorageDirectory; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +@RunWith(AndroidJUnit4.class) +public class EnvironmentTest { + private File dir; + + private Context getContext() { + return InstrumentationRegistry.getContext(); + } + + @Before + public void setUp() throws Exception { + dir = getContext().getDir("testing", Context.MODE_PRIVATE); + FileUtils.deleteContents(dir); + } + + @After + public void tearDown() throws Exception { + FileUtils.deleteContents(dir); + } + + @Test + public void testClassify_empty() { + assertEquals(0, classifyExternalStorageDirectory(dir)); + } + + @Test + public void testClassify_emptyDirs() { + Environment.buildPath(dir, "DCIM").mkdirs(); + Environment.buildPath(dir, "DCIM", "January").mkdirs(); + Environment.buildPath(dir, "Downloads").mkdirs(); + Environment.buildPath(dir, "LOST.DIR").mkdirs(); + assertEquals(0, classifyExternalStorageDirectory(dir)); + } + + @Test + public void testClassify_emptyFactory() throws Exception { + Environment.buildPath(dir, "autorun.inf").createNewFile(); + Environment.buildPath(dir, "LaunchU3.exe").createNewFile(); + Environment.buildPath(dir, "LaunchPad.zip").createNewFile(); + assertEquals(0, classifyExternalStorageDirectory(dir)); + } + + @Test + public void testClassify_photos() throws Exception { + Environment.buildPath(dir, "DCIM").mkdirs(); + Environment.buildPath(dir, "DCIM", "IMG_1024.JPG").createNewFile(); + Environment.buildPath(dir, "Download").mkdirs(); + Environment.buildPath(dir, "Download", "foobar.pdf").createNewFile(); + assertEquals(HAS_DCIM | HAS_DOWNLOADS, classifyExternalStorageDirectory(dir)); + } + + @Test + public void testClassify_other() throws Exception { + Environment.buildPath(dir, "Android").mkdirs(); + Environment.buildPath(dir, "Android", "com.example").mkdirs(); + Environment.buildPath(dir, "Android", "com.example", "internal.dat").createNewFile(); + Environment.buildPath(dir, "Linux").mkdirs(); + Environment.buildPath(dir, "Linux", "install-amd64-minimal-20170907.iso").createNewFile(); + assertEquals(HAS_ANDROID | HAS_OTHER, classifyExternalStorageDirectory(dir)); + } + + @Test + public void testClassify_otherRoot() throws Exception { + Environment.buildPath(dir, "Taxes.pdf").createNewFile(); + assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir)); + } +} diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java index 3a751afaec7b..cd20192edfd6 100644 --- a/core/tests/coretests/src/android/os/FileUtilsTest.java +++ b/core/tests/coretests/src/android/os/FileUtilsTest.java @@ -21,15 +21,24 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import android.content.Context; import android.provider.DocumentsContract.Document; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import libcore.io.IoUtils; import com.google.android.collect.Sets; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; @@ -37,8 +46,8 @@ import java.io.FileWriter; import java.util.Arrays; import java.util.HashSet; -@MediumTest -public class FileUtilsTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class FileUtilsTest { private static final String TEST_DATA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @@ -47,10 +56,12 @@ public class FileUtilsTest extends AndroidTestCase { private File mCopyFile; private File mTarget; + private Context getContext() { + return InstrumentationRegistry.getContext(); + } - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mDir = getContext().getDir("testing", Context.MODE_PRIVATE); mTestFile = new File(mDir, "test.file"); mCopyFile = new File(mDir, "copy.file"); @@ -59,14 +70,15 @@ public class FileUtilsTest extends AndroidTestCase { FileUtils.deleteContents(mTarget); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { IoUtils.deleteContents(mDir); FileUtils.deleteContents(mTarget); } // TODO: test setPermissions(), getPermissions() + @Test public void testCopyFile() throws Exception { stageFile(mTestFile, TEST_DATA); assertFalse(mCopyFile.exists()); @@ -75,6 +87,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null)); } + @Test public void testCopyToFile() throws Exception { final String s = "Foo Bar"; assertFalse(mCopyFile.exists()); @@ -83,6 +96,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null)); } + @Test public void testIsFilenameSafe() throws Exception { assertTrue(FileUtils.isFilenameSafe(new File("foobar"))); assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23"))); @@ -90,6 +104,7 @@ public class FileUtilsTest extends AndroidTestCase { assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar"))); } + @Test public void testReadTextFile() throws Exception { stageFile(mTestFile, TEST_DATA); @@ -110,6 +125,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>")); } + @Test public void testReadTextFileWithZeroLengthFile() throws Exception { stageFile(mTestFile, TEST_DATA); new FileOutputStream(mTestFile).close(); // Zero out the file @@ -120,6 +136,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>")); } + @Test public void testContains() throws Exception { assertTrue(FileUtils.contains(new File("/"), new File("/moo.txt"))); assertTrue(FileUtils.contains(new File("/"), new File("/"))); @@ -137,11 +154,13 @@ public class FileUtilsTest extends AndroidTestCase { assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/sdcard.txt"))); } + @Test public void testDeleteOlderEmptyDir() throws Exception { FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS); assertDirContents(); } + @Test public void testDeleteOlderTypical() throws Exception { touch("file1", HOUR_IN_MILLIS); touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); @@ -152,6 +171,7 @@ public class FileUtilsTest extends AndroidTestCase { assertDirContents("file1", "file2", "file3"); } + @Test public void testDeleteOlderInFuture() throws Exception { touch("file1", -HOUR_IN_MILLIS); touch("file2", HOUR_IN_MILLIS); @@ -166,6 +186,7 @@ public class FileUtilsTest extends AndroidTestCase { assertDirContents("file1", "file2"); } + @Test public void testDeleteOlderOnlyAge() throws Exception { touch("file1", HOUR_IN_MILLIS); touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); @@ -177,6 +198,7 @@ public class FileUtilsTest extends AndroidTestCase { assertDirContents("file1"); } + @Test public void testDeleteOlderOnlyCount() throws Exception { touch("file1", HOUR_IN_MILLIS); touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); @@ -188,6 +210,7 @@ public class FileUtilsTest extends AndroidTestCase { assertDirContents("file1", "file2"); } + @Test public void testValidExtFilename() throws Exception { assertTrue(FileUtils.isValidExtFilename("a")); assertTrue(FileUtils.isValidExtFilename("foo.bar")); @@ -208,6 +231,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("foo.bar", FileUtils.buildValidExtFilename("foo.bar")); } + @Test public void testValidFatFilename() throws Exception { assertTrue(FileUtils.isValidFatFilename("a")); assertTrue(FileUtils.isValidFatFilename("foo bar.baz")); @@ -233,6 +257,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz")); } + @Test public void testTrimFilename() throws Exception { assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16)); assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16)); @@ -245,6 +270,7 @@ public class FileUtilsTest extends AndroidTestCase { assertEquals("a...z", FileUtils.trimFilename(unicode, 6)); } + @Test public void testBuildUniqueFile_normal() throws Exception { assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test")); assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); @@ -263,6 +289,7 @@ public class FileUtilsTest extends AndroidTestCase { FileUtils.buildUniqueFile(mTarget, "application/x-flac", "test.flac")); } + @Test public void testBuildUniqueFile_unknown() throws Exception { assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, "application/octet-stream", "test")); @@ -275,6 +302,7 @@ public class FileUtilsTest extends AndroidTestCase { assertNameEquals("test.lolz", FileUtils.buildUniqueFile(mTarget, "lolz/lolz", "test.lolz")); } + @Test public void testBuildUniqueFile_dir() throws Exception { assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test")); new File(mTarget, "test").mkdir(); @@ -288,6 +316,7 @@ public class FileUtilsTest extends AndroidTestCase { FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test.jpg")); } + @Test public void testBuildUniqueFile_increment() throws Exception { assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); new File(mTarget, "test.jpg").createNewFile(); @@ -298,6 +327,7 @@ public class FileUtilsTest extends AndroidTestCase { FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); } + @Test public void testBuildUniqueFile_mimeless() throws Exception { assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg")); new File(mTarget, "test.jpg").createNewFile(); @@ -312,6 +342,7 @@ public class FileUtilsTest extends AndroidTestCase { assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar")); } + @Test public void testRoundStorageSize() throws Exception { final long M128 = 128000000L; final long M256 = 256000000L; diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 03672756275d..77c6c3e1c193 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -420,7 +420,7 @@ public class SettingsBackupTest { Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, // TODO(b/67867469): Move autofill settings below to // BACKUP_BLACKLISTED_SYSTEM_SETTINGS once feature is moved out of experimental - Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION, + Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE, Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE, Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH, diff --git a/core/tests/coretests/src/android/util/KeyValueListParserTest.java b/core/tests/coretests/src/android/util/KeyValueListParserTest.java new file mode 100644 index 000000000000..038f0b7efaa3 --- /dev/null +++ b/core/tests/coretests/src/android/util/KeyValueListParserTest.java @@ -0,0 +1,109 @@ +/* + * 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.util; + +import static org.junit.Assert.assertEquals; + +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link KeyValueListParser}. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class KeyValueListParserTest { + private static final String TAG = "KeyValueListParserTest"; + private static final int[] DEFAULT = {1, 2, 3, 4}; + + private KeyValueListParser mParser; + + @Before + public void setUp() { + mParser = new KeyValueListParser(','); + } + + @Test + public void testParseIntArrayNullInput() throws Exception { + mParser.setString(null); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(DEFAULT, result); + } + + @Test + public void testParseIntArrayEmptyInput() throws Exception { + mParser.setString("test="); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(DEFAULT, result); + } + + @Test + public void testParseIntArrayNullKey() throws Exception { + mParser.setString("foo=bar,test=100:200,baz=123"); + int[] result = mParser.getIntArray(null, DEFAULT); + assertEquals(DEFAULT, result); + } + + @Test + public void testParseIntArrayComplexInput() throws Exception { + mParser.setString("foo=bar,test=100:200,baz=123"); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(2, result.length); + assertEquals(100, result[0]); // respect order + assertEquals(200, result[1]); + } + + @Test + public void testParseIntArrayLeadingSep() throws Exception { + mParser.setString("test=:4:5:6"); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(DEFAULT, result); + } + + @Test + public void testParseIntArrayEmptyItem() throws Exception { + mParser.setString("test=:4::6"); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(DEFAULT, result); + } + + @Test + public void testParseIntArrayTrailingSep() throws Exception { + mParser.setString("test=4:5:6:"); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(3, result.length); + assertEquals(4, result[0]); // respect order + assertEquals(5, result[1]); + assertEquals(6, result[2]); + } + + @Test + public void testParseIntArrayGoodData() throws Exception { + mParser.setString("test=4:5:6"); + int[] result = mParser.getIntArray("test", DEFAULT); + assertEquals(3, result.length); + assertEquals(4, result[0]); // respect order + assertEquals(5, result[1]); + assertEquals(6, result[2]); + } +} diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index a4e3988e686f..449e3743e3aa 100644 --- a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.policy; +package com.android.internal.accessibility; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.AlertDialog; @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.os.Handler; @@ -38,7 +39,7 @@ import android.view.accessibility.IAccessibilityManager; import android.widget.Toast; import com.android.internal.R; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.server.policy.AccessibilityShortcutController.FrameworkObjectProvider; +import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider; import org.junit.After; import org.junit.Before; @@ -50,6 +51,7 @@ import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import java.util.Collections; +import java.util.Map; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED; @@ -58,7 +60,10 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SER import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; + +import static org.junit.Assert.fail; import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyObject; @@ -72,6 +77,7 @@ import static org.mockito.Mockito.when; @RunWith(AndroidJUnit4.class) public class AccessibilityShortcutControllerTest { private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name"; + private static final String SERVICE_NAME_SUMMARY = "Summary"; private static final long VIBRATOR_PATTERN_1 = 100L; private static final long VIBRATOR_PATTERN_2 = 150L; private static final int[] VIBRATOR_PATTERN_INT = {(int) VIBRATOR_PATTERN_1, @@ -95,6 +101,7 @@ public class AccessibilityShortcutControllerTest { private @Mock Toast mToast; private @Mock Vibrator mVibrator; private @Mock ApplicationInfo mApplicationInfo; + private @Mock PackageManager mPackageManager; private MockContentResolver mContentResolver; private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); @@ -108,6 +115,10 @@ public class AccessibilityShortcutControllerTest { when(mContext.getResources()).thenReturn(mResources); when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + + // We're not checking the text. Just prevent us crashing when getting text. + when(mPackageManager.getText(any(), anyInt(), any())).thenReturn("text"); mContentResolver = new MockContentResolver(mContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); @@ -125,6 +136,7 @@ public class AccessibilityShortcutControllerTest { .thenReturn(mAlertDialogBuilder); when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt())) .thenReturn(mToast); + when(mFrameworkObjectProvider.getSystemUiContext()).thenReturn(mContext); when(mResources.getString(anyInt())).thenReturn("Howdy %s"); when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT); @@ -134,6 +146,7 @@ public class AccessibilityShortcutControllerTest { when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo); when(mServiceInfo.getComponentName()) .thenReturn(ComponentName.unflattenFromString(SERVICE_NAME_STRING)); + when(mServiceInfo.loadSummary(any())).thenReturn(SERVICE_NAME_SUMMARY); when(mAlertDialogBuilder.setTitle(anyInt())).thenReturn(mAlertDialogBuilder); when(mAlertDialogBuilder.setCancelable(anyBoolean())).thenReturn(mAlertDialogBuilder); @@ -369,6 +382,33 @@ public class AccessibilityShortcutControllerTest { verify(mAccessibilityManagerService).performAccessibilityShortcut(); } + @Test + public void getFrameworkFeatureMap_shouldBeNonNullAndUnmodifiable() { + Map<ComponentName, AccessibilityShortcutController.ToggleableFrameworkFeatureInfo> + frameworkFeatureMap = + AccessibilityShortcutController.getFrameworkShortcutFeaturesMap(); + assertTrue("Framework features not supported", frameworkFeatureMap.size() > 0); + + try { + frameworkFeatureMap.clear(); + fail("Framework feature map should be unmodifieable"); + } catch (UnsupportedOperationException e) { + // Expected + } + } + + @Test + public void testOnAccessibilityShortcut_forFrameworkFeature_callsServiceWithNoToast() + throws Exception { + configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); + configureFirstFrameworkFeature(); + Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1); + getController().performAccessibilityShortcut(); + + verifyZeroInteractions(mToast); + verify(mAccessibilityManagerService).performAccessibilityShortcut(); + } + private void configureNoShortcutService() { Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); } @@ -378,6 +418,14 @@ public class AccessibilityShortcutControllerTest { mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING); } + private void configureFirstFrameworkFeature() { + ComponentName featureComponentName = + (ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() + .keySet().toArray()[0]; + Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + featureComponentName.flattenToString()); + } + private void configureShortcutEnabled(int enabledValue) { final boolean enabled; final boolean lockscreen; diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk index f2d205885c20..6330b8eb4183 100644 --- a/core/tests/featureflagtests/Android.mk +++ b/core/tests/featureflagtests/Android.mk @@ -10,7 +10,7 @@ LOCAL_SRC_FILES := \ LOCAL_DX_FLAGS := --core-library LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib android-support-test -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests LOCAL_CERTIFICATE := platform diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk index 4c2e2247a113..57e205994c4e 100644 --- a/core/tests/systemproperties/Android.mk +++ b/core/tests/systemproperties/Android.mk @@ -10,7 +10,7 @@ LOCAL_SRC_FILES := \ LOCAL_DX_FLAGS := --core-library LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests LOCAL_CERTIFICATE := platform diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk index 88112561f1d0..be1ab1f73d9f 100644 --- a/core/tests/utillib/Android.mk +++ b/core/tests/utillib/Android.mk @@ -19,7 +19,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := frameworks-core-util-lib -LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test +LOCAL_STATIC_JAVA_LIBRARIES := junit +LOCAL_JAVA_LIBRARIES := android.test.base include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk index 233d070f9507..2dc105932f04 100644 --- a/core/tests/utiltests/Android.mk +++ b/core/tests/utiltests/Android.mk @@ -19,7 +19,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ frameworks-base-testutils \ mockito-target-minus-junit4 \ -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock LOCAL_PACKAGE_NAME := FrameworksUtilTests diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index b3bba07296d2..74f8c71da09f 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -404,6 +404,8 @@ key 484 B FUNCTION # key 503 KEY_BRL_DOT7 # key 504 KEY_BRL_DOT8 +key 522 STAR +key 523 POUND key 580 APP_SWITCH key 582 VOICE_ASSIST diff --git a/data/keyboards/Generic_Iot.kl b/data/keyboards/Generic_Iot.kl deleted file mode 100644 index 89df22462fc7..000000000000 --- a/data/keyboards/Generic_Iot.kl +++ /dev/null @@ -1,443 +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. - -# -# Generic key layout file for full alphabetic US English PC style external keyboards. -# -# This file is intentionally very generic and is intended to support a broad range of keyboards. -# Do not edit the generic key layout to support a specific keyboard; instead, create -# a new key layout file with the required keyboard configuration. -# - -key 1 ESCAPE -key 2 1 -key 3 2 -key 4 3 -key 5 4 -key 6 5 -key 7 6 -key 8 7 -key 9 8 -key 10 9 -key 11 0 -key 12 MINUS -key 13 EQUALS -key 14 DEL -key 15 TAB -key 16 Q -key 17 W -key 18 E -key 19 R -key 20 T -key 21 Y -key 22 U -key 23 I -key 24 O -key 25 P -key 26 LEFT_BRACKET -key 27 RIGHT_BRACKET -key 28 ENTER -key 29 CTRL_LEFT -key 30 A -key 31 S -key 32 D -key 33 F -key 34 G -key 35 H -key 36 J -key 37 K -key 38 L -key 39 SEMICOLON -key 40 APOSTROPHE -key 41 GRAVE -key 42 SHIFT_LEFT -key 43 BACKSLASH -key 44 Z -key 45 X -key 46 C -key 47 V -key 48 B -key 49 N -key 50 M -key 51 COMMA -key 52 PERIOD -key 53 SLASH -key 54 SHIFT_RIGHT -key 55 NUMPAD_MULTIPLY -key 56 ALT_LEFT -key 57 SPACE -key 58 CAPS_LOCK -key 59 F1 -key 60 F2 -key 61 F3 -key 62 F4 -key 63 F5 -key 64 F6 -key 65 F7 -key 66 F8 -key 67 F9 -key 68 F10 -key 69 NUM_LOCK -key 70 SCROLL_LOCK -key 71 NUMPAD_7 -key 72 NUMPAD_8 -key 73 NUMPAD_9 -key 74 NUMPAD_SUBTRACT -key 75 NUMPAD_4 -key 76 NUMPAD_5 -key 77 NUMPAD_6 -key 78 NUMPAD_ADD -key 79 NUMPAD_1 -key 80 NUMPAD_2 -key 81 NUMPAD_3 -key 82 NUMPAD_0 -key 83 NUMPAD_DOT -# key 84 (undefined) -key 85 ZENKAKU_HANKAKU -key 86 BACKSLASH -key 87 F11 -key 88 F12 -key 89 RO -# key 90 "KEY_KATAKANA" -# key 91 "KEY_HIRAGANA" -key 92 HENKAN -key 93 KATAKANA_HIRAGANA -key 94 MUHENKAN -key 95 NUMPAD_COMMA -key 96 NUMPAD_ENTER -key 97 CTRL_RIGHT -key 98 NUMPAD_DIVIDE -key 99 SYSRQ -key 100 ALT_RIGHT -# key 101 "KEY_LINEFEED" -key 102 MOVE_HOME -key 103 DPAD_UP -key 104 PAGE_UP -key 105 DPAD_LEFT -key 106 DPAD_RIGHT -key 107 MOVE_END -key 108 DPAD_DOWN -key 109 PAGE_DOWN -key 110 INSERT -key 111 FORWARD_DEL -# key 112 "KEY_MACRO" -key 113 VOLUME_MUTE -key 114 VOLUME_DOWN -key 115 VOLUME_UP -key 116 POWER -key 117 NUMPAD_EQUALS -# key 118 "KEY_KPPLUSMINUS" -key 119 BREAK -# key 120 (undefined) -key 121 NUMPAD_COMMA -key 122 KANA -key 123 EISU -key 124 YEN -key 125 META_LEFT -key 126 META_RIGHT -key 127 MENU -key 128 MEDIA_STOP -# key 129 "KEY_AGAIN" -# key 130 "KEY_PROPS" -# key 131 "KEY_UNDO" -# key 132 "KEY_FRONT" -key 133 COPY -# key 134 "KEY_OPEN" -key 135 PASTE -# key 136 "KEY_FIND" -key 137 CUT -# key 138 "KEY_HELP" -key 139 MENU -key 140 CALCULATOR -# key 141 "KEY_SETUP" -key 142 SLEEP -key 143 WAKEUP -# key 144 "KEY_FILE" -# key 145 "KEY_SENDFILE" -# key 146 "KEY_DELETEFILE" -# key 147 "KEY_XFER" -# key 148 "KEY_PROG1" -# key 149 "KEY_PROG2" -key 150 EXPLORER -# key 151 "KEY_MSDOS" -key 152 POWER -# key 153 "KEY_DIRECTION" -# key 154 "KEY_CYCLEWINDOWS" -key 155 ENVELOPE -key 156 BOOKMARK -# key 157 "KEY_COMPUTER" -key 158 BACK -key 159 FORWARD -key 160 MEDIA_CLOSE -key 161 MEDIA_EJECT -key 162 MEDIA_EJECT -key 163 MEDIA_NEXT -key 164 MEDIA_PLAY_PAUSE -key 165 MEDIA_PREVIOUS -key 166 MEDIA_STOP -key 167 MEDIA_RECORD -key 168 MEDIA_REWIND -key 169 CALL -# key 170 "KEY_ISO" -key 171 MUSIC -key 172 HOME -# key 173 "KEY_REFRESH" -# key 174 "KEY_EXIT" -# key 175 "KEY_MOVE" -# key 176 "KEY_EDIT" -key 177 PAGE_UP -key 178 PAGE_DOWN -key 179 NUMPAD_LEFT_PAREN -key 180 NUMPAD_RIGHT_PAREN -# key 181 "KEY_NEW" -# key 182 "KEY_REDO" -# key 183 F13 -# key 184 F14 -# key 185 F15 -# key 186 F16 -# key 187 F17 -# key 188 F18 -# key 189 F19 -# key 190 F20 -# key 191 F21 -# key 192 F22 -# key 193 F23 -# key 194 F24 -# key 195 (undefined) -# key 196 (undefined) -# key 197 (undefined) -# key 198 (undefined) -# key 199 (undefined) -key 200 MEDIA_PLAY -key 201 MEDIA_PAUSE -# key 202 "KEY_PROG3" -# key 203 "KEY_PROG4" -# key 204 (undefined) -# key 205 "KEY_SUSPEND" -# key 206 "KEY_CLOSE" -key 207 MEDIA_PLAY -key 208 MEDIA_FAST_FORWARD -# key 209 "KEY_BASSBOOST" -# key 210 "KEY_PRINT" -# key 211 "KEY_HP" -key 212 CAMERA -key 213 MUSIC -# key 214 "KEY_QUESTION" -key 215 ENVELOPE -# key 216 "KEY_CHAT" -key 217 SEARCH -# key 218 "KEY_CONNECT" -# key 219 "KEY_FINANCE" -# key 220 "KEY_SPORT" -# key 221 "KEY_SHOP" -# key 222 "KEY_ALTERASE" -# key 223 "KEY_CANCEL" -key 224 BRIGHTNESS_DOWN -key 225 BRIGHTNESS_UP -key 226 HEADSETHOOK -key 227 POUND -key 228 STAR - -key 256 BUTTON_1 -key 257 BUTTON_2 -key 258 BUTTON_3 -key 259 BUTTON_4 -key 260 BUTTON_5 -key 261 BUTTON_6 -key 262 BUTTON_7 -key 263 BUTTON_8 -key 264 BUTTON_9 -key 265 BUTTON_10 -key 266 BUTTON_11 -key 267 BUTTON_12 -key 268 BUTTON_13 -key 269 BUTTON_14 -key 270 BUTTON_15 -key 271 BUTTON_16 - -key 288 BUTTON_1 -key 289 BUTTON_2 -key 290 BUTTON_3 -key 291 BUTTON_4 -key 292 BUTTON_5 -key 293 BUTTON_6 -key 294 BUTTON_7 -key 295 BUTTON_8 -key 296 BUTTON_9 -key 297 BUTTON_10 -key 298 BUTTON_11 -key 299 BUTTON_12 -key 300 BUTTON_13 -key 301 BUTTON_14 -key 302 BUTTON_15 -key 303 BUTTON_16 - - -key 304 BUTTON_A -key 305 BUTTON_B -key 306 BUTTON_C -key 307 BUTTON_X -key 308 BUTTON_Y -key 309 BUTTON_Z -key 310 BUTTON_L1 -key 311 BUTTON_R1 -key 312 BUTTON_L2 -key 313 BUTTON_R2 -key 314 BUTTON_SELECT -key 315 BUTTON_START -key 316 BUTTON_MODE -key 317 BUTTON_THUMBL -key 318 BUTTON_THUMBR - - -# key 352 "KEY_OK" -key 353 DPAD_CENTER -# key 354 "KEY_GOTO" -# key 355 "KEY_CLEAR" -# key 356 "KEY_POWER2" -# key 357 "KEY_OPTION" -# key 358 "KEY_INFO" -# key 359 "KEY_TIME" -# key 360 "KEY_VENDOR" -# key 361 "KEY_ARCHIVE" -key 362 GUIDE -# key 363 "KEY_CHANNEL" -# key 364 "KEY_FAVORITES" -# key 365 "KEY_EPG" -key 366 DVR -# key 367 "KEY_MHP" -# key 368 "KEY_LANGUAGE" -# key 369 "KEY_TITLE" -# key 370 "KEY_SUBTITLE" -# key 371 "KEY_ANGLE" -# key 372 "KEY_ZOOM" -# key 373 "KEY_MODE" -# key 374 "KEY_KEYBOARD" -# key 375 "KEY_SCREEN" -# key 376 "KEY_PC" -key 377 TV -# key 378 "KEY_TV2" -# key 379 "KEY_VCR" -# key 380 "KEY_VCR2" -# key 381 "KEY_SAT" -# key 382 "KEY_SAT2" -# key 383 "KEY_CD" -# key 384 "KEY_TAPE" -# key 385 "KEY_RADIO" -# key 386 "KEY_TUNER" -# key 387 "KEY_PLAYER" -# key 388 "KEY_TEXT" -# key 389 "KEY_DVD" -# key 390 "KEY_AUX" -# key 391 "KEY_MP3" -# key 392 "KEY_AUDIO" -# key 393 "KEY_VIDEO" -# key 394 "KEY_DIRECTORY" -# key 395 "KEY_LIST" -# key 396 "KEY_MEMO" -key 397 CALENDAR -# key 398 "KEY_RED" -# key 399 "KEY_GREEN" -# key 400 "KEY_YELLOW" -# key 401 "KEY_BLUE" -key 402 CHANNEL_UP -key 403 CHANNEL_DOWN -# key 404 "KEY_FIRST" -# key 405 "KEY_LAST" -# key 406 "KEY_AB" -# key 407 "KEY_NEXT" -# key 408 "KEY_RESTART" -# key 409 "KEY_SLOW" -# key 410 "KEY_SHUFFLE" -# key 411 "KEY_BREAK" -# key 412 "KEY_PREVIOUS" -# key 413 "KEY_DIGITS" -# key 414 "KEY_TEEN" -# key 415 "KEY_TWEN" - -key 429 CONTACTS - -# key 448 "KEY_DEL_EOL" -# key 449 "KEY_DEL_EOS" -# key 450 "KEY_INS_LINE" -# key 451 "KEY_DEL_LINE" - - -key 464 FUNCTION -key 465 ESCAPE FUNCTION -key 466 F1 FUNCTION -key 467 F2 FUNCTION -key 468 F3 FUNCTION -key 469 F4 FUNCTION -key 470 F5 FUNCTION -key 471 F6 FUNCTION -key 472 F7 FUNCTION -key 473 F8 FUNCTION -key 474 F9 FUNCTION -key 475 F10 FUNCTION -key 476 F11 FUNCTION -key 477 F12 FUNCTION -key 478 1 FUNCTION -key 479 2 FUNCTION -key 480 D FUNCTION -key 481 E FUNCTION -key 482 F FUNCTION -key 483 S FUNCTION -key 484 B FUNCTION - - -# key 497 KEY_BRL_DOT1 -# key 498 KEY_BRL_DOT2 -# key 499 KEY_BRL_DOT3 -# key 500 KEY_BRL_DOT4 -# key 501 KEY_BRL_DOT5 -# key 502 KEY_BRL_DOT6 -# key 503 KEY_BRL_DOT7 -# key 504 KEY_BRL_DOT8 - -key 580 APP_SWITCH -key 582 VOICE_ASSIST - -# Keys defined by HID usages -key usage 0x0c006F BRIGHTNESS_UP -key usage 0x0c0070 BRIGHTNESS_DOWN - -# Joystick and game controller axes. -# Axes that are not mapped will be assigned generic axis numbers by the input subsystem. -axis 0x00 X -axis 0x01 Y -axis 0x02 Z -axis 0x03 RX -axis 0x04 RY -axis 0x05 RZ -axis 0x06 THROTTLE -axis 0x07 RUDDER -axis 0x08 WHEEL -axis 0x09 GAS -axis 0x0a BRAKE -axis 0x10 HAT_X -axis 0x11 HAT_Y - -# LEDs -led 0x00 NUM_LOCK -led 0x01 CAPS_LOCK -led 0x02 SCROLL_LOCK -led 0x03 COMPOSE -led 0x04 KANA -led 0x05 SLEEP -led 0x06 SUSPEND -led 0x07 MUTE -led 0x08 MISC -led 0x09 MAIL -led 0x0a CHARGING diff --git a/keystore/java/android/security/AttestedKeyPair.java b/keystore/java/android/security/AttestedKeyPair.java new file mode 100644 index 000000000000..c6bff5c11a5d --- /dev/null +++ b/keystore/java/android/security/AttestedKeyPair.java @@ -0,0 +1,75 @@ +/* + * 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.security; + +import java.security.KeyPair; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * The {@code AttestedKeyPair} class contains a {@code KeyPair} instance of + * keys generated by Keystore and owned by KeyChain, as well as an attestation + * record for the key. + * + * <p>Such keys can be obtained by calling + * {@link android.app.admin.DevicePolicyManager#generateKeyPair}. + */ + +public final class AttestedKeyPair { + private final KeyPair mKeyPair; + private final Certificate[] mAttestationRecord; + + /** + * @hide Only created by the platform, no need to expose as public API. + */ + public AttestedKeyPair(KeyPair keyPair, Certificate[] attestationRecord) { + mKeyPair = keyPair; + mAttestationRecord = attestationRecord; + } + + /** + * Returns the generated key pair associated with the attestation record + * in this instance. + */ + public KeyPair getKeyPair() { + return mKeyPair; + } + + /** + * Returns the attestation record for the key pair in this instance. + * + * The attestation record is a chain of certificates. The leaf certificate links to the public + * key of this key pair and other properties of the key or the device. If the key is in secure + * hardware, and if the secure hardware supports attestation, the leaf certificate will be + * signed by a chain of certificates rooted at a trustworthy CA key. Otherwise the chain will be + * rooted at an untrusted certificate. + * + * The attestation record could be for properties of the key, or include device identifiers. + * + * See {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge} + * and <a href="https://developer.android.com/training/articles/security-key-attestation.html"> + * Key Attestation</a> for the format of the attestation record inside the certificate. + */ + public List<Certificate> getAttestationRecord() { + if (mAttestationRecord == null) { + return new ArrayList(); + } + return Arrays.asList(mAttestationRecord); + } +} diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index 635432da7942..b4331b21cf13 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -16,6 +16,7 @@ package android.security; import android.content.pm.StringParceledListSlice; +import android.security.keystore.ParcelableKeyGenParameterSpec; /** * Caller is required to ensure that {@link KeyStore#unlock @@ -31,6 +32,8 @@ interface IKeyChainService { boolean isUserSelectable(String alias); void setUserSelectable(String alias, boolean isUserSelectable); + boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); + // APIs used by CertInstaller and DevicePolicyManager String installCaCertificate(in byte[] caCertificate); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index ed40b77be4a4..87677d479471 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -195,7 +195,7 @@ import javax.security.auth.x500.X500Principal; * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( * KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); - * keyGenerator.initialize( + * keyGenerator.init( * new KeyGenParameterSpec.Builder("key2", * KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) * .setBlockModes(KeyProperties.BLOCK_MODE_GCM) @@ -219,7 +219,7 @@ import javax.security.auth.x500.X500Principal; * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( * KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore"); - * keyGenerator.initialize( + * keyGenerator.init( * new KeyGenParameterSpec.Builder("key2", KeyProperties.PURPOSE_SIGN).build()); * SecretKey key = keyGenerator.generateKey(); * Mac mac = Mac.getInstance("HmacSHA256"); diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl new file mode 100644 index 000000000000..3fb7b4f99463 --- /dev/null +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.aidl @@ -0,0 +1,19 @@ +/* + * 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.security.keystore; + +parcelable ParcelableKeyGenParameterSpec; diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java new file mode 100644 index 000000000000..b15e0a221c6f --- /dev/null +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java @@ -0,0 +1,170 @@ +/* + * 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.security.keystore; + +import android.os.Parcelable; +import android.os.Parcel; + +import java.math.BigInteger; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +/** + * A parcelable version of KeyGenParameterSpec + * @hide only used for communicating with the DPMS. + */ +public final class ParcelableKeyGenParameterSpec implements Parcelable { + private static final int ALGORITHM_PARAMETER_SPEC_NONE = 1; + private static final int ALGORITHM_PARAMETER_SPEC_RSA = 2; + private static final int ALGORITHM_PARAMETER_SPEC_EC = 3; + + private final KeyGenParameterSpec mSpec; + + public ParcelableKeyGenParameterSpec( + KeyGenParameterSpec spec) { + mSpec = spec; + } + + public int describeContents() { + return 0; + } + + private static void writeOptionalDate(Parcel out, Date date) { + if (date != null) { + out.writeBoolean(true); + out.writeLong(date.getTime()); + } else { + out.writeBoolean(false); + } + } + + public void writeToParcel(Parcel out, int flags) { + out.writeString(mSpec.getKeystoreAlias()); + out.writeInt(mSpec.getPurposes()); + out.writeInt(mSpec.getUid()); + out.writeInt(mSpec.getKeySize()); + + // Only needs to support RSAKeyGenParameterSpec and ECGenParameterSpec. + AlgorithmParameterSpec algoSpec = mSpec.getAlgorithmParameterSpec(); + if (algoSpec == null) { + out.writeInt(ALGORITHM_PARAMETER_SPEC_NONE); + } else if (algoSpec instanceof RSAKeyGenParameterSpec) { + RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algoSpec; + out.writeInt(ALGORITHM_PARAMETER_SPEC_RSA); + out.writeInt(rsaSpec.getKeysize()); + out.writeByteArray(rsaSpec.getPublicExponent().toByteArray()); + } else if (algoSpec instanceof ECGenParameterSpec) { + ECGenParameterSpec ecSpec = (ECGenParameterSpec) algoSpec; + out.writeInt(ALGORITHM_PARAMETER_SPEC_EC); + out.writeString(ecSpec.getName()); + } else { + throw new IllegalArgumentException( + String.format("Unknown algorithm parameter spec: %s", algoSpec.getClass())); + } + out.writeByteArray(mSpec.getCertificateSubject().getEncoded()); + out.writeByteArray(mSpec.getCertificateSerialNumber().toByteArray()); + writeOptionalDate(out, mSpec.getCertificateNotBefore()); + writeOptionalDate(out, mSpec.getCertificateNotAfter()); + writeOptionalDate(out, mSpec.getKeyValidityStart()); + writeOptionalDate(out, mSpec.getKeyValidityForOriginationEnd()); + writeOptionalDate(out, mSpec.getKeyValidityForConsumptionEnd()); + out.writeStringArray(mSpec.getDigests()); + out.writeStringArray(mSpec.getEncryptionPaddings()); + out.writeStringArray(mSpec.getSignaturePaddings()); + out.writeStringArray(mSpec.getBlockModes()); + out.writeBoolean(mSpec.isRandomizedEncryptionRequired()); + out.writeBoolean(mSpec.isUserAuthenticationRequired()); + out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds()); + out.writeByteArray(mSpec.getAttestationChallenge()); + out.writeBoolean(mSpec.isUniqueIdIncluded()); + out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody()); + out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment()); + } + + private static Date readDateOrNull(Parcel in) { + boolean hasDate = in.readBoolean(); + if (hasDate) { + return new Date(in.readLong()); + } else { + return null; + } + } + + private ParcelableKeyGenParameterSpec(Parcel in) { + String keystoreAlias = in.readString(); + int purposes = in.readInt(); + KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, purposes); + builder.setUid(in.readInt()); + builder.setKeySize(in.readInt()); + + int keySpecType = in.readInt(); + AlgorithmParameterSpec algorithmSpec = null; + if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) { + algorithmSpec = null; + } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_RSA) { + int rsaKeySize = in.readInt(); + BigInteger publicExponent = new BigInteger(in.createByteArray()); + algorithmSpec = new RSAKeyGenParameterSpec(rsaKeySize, publicExponent); + } else if (keySpecType == ALGORITHM_PARAMETER_SPEC_EC) { + String stdName = in.readString(); + algorithmSpec = new ECGenParameterSpec(stdName); + } else { + throw new IllegalArgumentException( + String.format("Unknown algorithm parameter spec: %d", algorithmSpec)); + } + builder.setAlgorithmParameterSpec(algorithmSpec); + builder.setCertificateSubject(new X500Principal(in.createByteArray())); + builder.setCertificateSerialNumber(new BigInteger(in.createByteArray())); + builder.setCertificateNotBefore(readDateOrNull(in)); + builder.setCertificateNotAfter(readDateOrNull(in)); + builder.setKeyValidityStart(readDateOrNull(in)); + builder.setKeyValidityForOriginationEnd(readDateOrNull(in)); + builder.setKeyValidityForConsumptionEnd(readDateOrNull(in)); + builder.setDigests(in.createStringArray()); + builder.setEncryptionPaddings(in.createStringArray()); + builder.setSignaturePaddings(in.createStringArray()); + builder.setBlockModes(in.createStringArray()); + builder.setRandomizedEncryptionRequired(in.readBoolean()); + builder.setUserAuthenticationRequired(in.readBoolean()); + builder.setUserAuthenticationValidityDurationSeconds(in.readInt()); + builder.setAttestationChallenge(in.createByteArray()); + builder.setUniqueIdIncluded(in.readBoolean()); + builder.setUserAuthenticationValidWhileOnBody(in.readBoolean()); + builder.setInvalidatedByBiometricEnrollment(in.readBoolean()); + mSpec = builder.build(); + } + + public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() { + @Override + public ParcelableKeyGenParameterSpec createFromParcel(Parcel in) { + return new ParcelableKeyGenParameterSpec(in); + } + + @Override + public ParcelableKeyGenParameterSpec[] newArray(int size) { + return new ParcelableKeyGenParameterSpec[size]; + } + }; + + public KeyGenParameterSpec getSpec() { + return mSpec; + } +} diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk new file mode 100644 index 000000000000..51adde4d68af --- /dev/null +++ b/keystore/tests/Android.mk @@ -0,0 +1,34 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# LOCAL_MODULE := keystore +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + legacy-android-test + +LOCAL_PACKAGE_NAME := KeystoreTests + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml new file mode 100644 index 000000000000..9bf2d0c761e6 --- /dev/null +++ b/keystore/tests/AndroidManifest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.tests"> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.tests" + android:label="Tests for Keystore"> + </instrumentation> +</manifest> + diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java new file mode 100644 index 000000000000..73b489f98e1d --- /dev/null +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -0,0 +1,180 @@ +/* + * 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.security; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import android.os.Parcel; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.ParcelableKeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.support.test.runner.AndroidJUnit4; +import java.math.BigInteger; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Date; +import javax.security.auth.x500.X500Principal; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Unit tests for {@link ParcelableKeyGenParameterSpec}. */ +@RunWith(AndroidJUnit4.class) +public final class ParcelableKeyGenParameterSpecTest { + static final String ALIAS = "keystore-alias"; + static final String ANOTHER_ALIAS = "another-keystore-alias"; + static final int KEY_PURPOSES = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY; + static final int UID = 1230; + static final int KEYSIZE = 2048; + static final X500Principal SUBJECT = new X500Principal("CN=subject"); + static final BigInteger SERIAL = new BigInteger("1234567890"); + static final Date NOT_BEFORE = new Date(1511799590); + static final Date NOT_AFTER = new Date(1511899590); + static final Date KEY_VALIDITY_START = new Date(1511799591); + static final Date KEY_VALIDITY_FOR_ORIG_END = new Date(1511799593); + static final Date KEY_VALIDITY_FOR_CONSUMPTION_END = new Date(1511799594); + static final String DIGEST = KeyProperties.DIGEST_SHA256; + static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; + static final String SIGNATURE_PADDING = KeyProperties.SIGNATURE_PADDING_RSA_PSS; + static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC; + static final int USER_AUTHENTICATION_DURATION = 300; + static final byte[] ATTESTATION_CHALLENGE = new byte[] {'c', 'h'}; + + KeyGenParameterSpec configureDefaultSpec() { + return new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) + .setUid(UID) + .setKeySize(KEYSIZE) + .setCertificateSubject(SUBJECT) + .setCertificateSerialNumber(SERIAL) + .setCertificateNotBefore(NOT_BEFORE) + .setCertificateNotAfter(NOT_AFTER) + .setKeyValidityStart(KEY_VALIDITY_START) + .setKeyValidityForOriginationEnd(KEY_VALIDITY_FOR_ORIG_END) + .setKeyValidityForConsumptionEnd(KEY_VALIDITY_FOR_CONSUMPTION_END) + .setDigests(DIGEST) + .setEncryptionPaddings(ENCRYPTION_PADDING) + .setSignaturePaddings(SIGNATURE_PADDING) + .setBlockModes(BLOCK_MODE) + .setRandomizedEncryptionRequired(true) + .setUserAuthenticationRequired(true) + .setUserAuthenticationValidityDurationSeconds(USER_AUTHENTICATION_DURATION) + .setAttestationChallenge(ATTESTATION_CHALLENGE) + .setUniqueIdIncluded(true) + .setUserAuthenticationValidWhileOnBody(true) + .setInvalidatedByBiometricEnrollment(true) + .build(); + } + + void validateSpecValues(KeyGenParameterSpec spec, int uid, String alias) { + assertThat(spec.getKeystoreAlias(), is(alias)); + assertThat(spec.getPurposes(), is(KEY_PURPOSES)); + assertThat(spec.getUid(), is(uid)); + assertThat(spec.getKeySize(), is(KEYSIZE)); + assertThat(spec.getCertificateSubject(), is(SUBJECT)); + assertThat(spec.getCertificateSerialNumber(), is(SERIAL)); + assertThat(spec.getCertificateNotBefore(), is(NOT_BEFORE)); + assertThat(spec.getCertificateNotAfter(), is(NOT_AFTER)); + assertThat(spec.getKeyValidityStart(), is(KEY_VALIDITY_START)); + assertThat(spec.getKeyValidityForOriginationEnd(), is(KEY_VALIDITY_FOR_ORIG_END)); + assertThat(spec.getKeyValidityForConsumptionEnd(), is(KEY_VALIDITY_FOR_CONSUMPTION_END)); + assertThat(spec.getDigests(), is(new String[] {DIGEST})); + assertThat(spec.getEncryptionPaddings(), is(new String[] {ENCRYPTION_PADDING})); + assertThat(spec.getSignaturePaddings(), is(new String[] {SIGNATURE_PADDING})); + assertThat(spec.getBlockModes(), is(new String[] {BLOCK_MODE})); + assertThat(spec.isRandomizedEncryptionRequired(), is(true)); + assertThat(spec.isUserAuthenticationRequired(), is(true)); + assertThat( + spec.getUserAuthenticationValidityDurationSeconds(), + is(USER_AUTHENTICATION_DURATION)); + assertThat(spec.getAttestationChallenge(), is(ATTESTATION_CHALLENGE)); + assertThat(spec.isUniqueIdIncluded(), is(true)); + assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true)); + assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true)); + } + + private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) { + Parcel parcel = Parcel.obtain(); + spec.writeToParcel(parcel, spec.describeContents()); + + parcel.setDataPosition(0); + return parcel; + } + + @Test + public void testParcelingWithAllValues() { + ParcelableKeyGenParameterSpec spec = + new ParcelableKeyGenParameterSpec(configureDefaultSpec()); + Parcel parcel = parcelForReading(spec); + ParcelableKeyGenParameterSpec fromParcel = + ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel); + validateSpecValues(fromParcel.getSpec(), UID, ALIAS); + assertThat(parcel.dataAvail(), is(0)); + } + + @Test + public void testParcelingWithNullValues() { + ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( + new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES).build()); + + Parcel parcel = parcelForReading(spec); + KeyGenParameterSpec fromParcel = ParcelableKeyGenParameterSpec.CREATOR + .createFromParcel(parcel) + .getSpec(); + assertThat(fromParcel.getKeystoreAlias(), is(ALIAS)); + assertThat(fromParcel.getPurposes(), is(KEY_PURPOSES)); + assertThat(fromParcel.getCertificateNotBefore(), is(new Date(0L))); + assertThat(fromParcel.getCertificateNotAfter(), is(new Date(2461449600000L))); + assertThat(parcel.dataAvail(), is(0)); + } + + @Test + public void testParcelingRSAAlgoParameter() { + RSAKeyGenParameterSpec rsaSpec = + new RSAKeyGenParameterSpec(2048, new BigInteger("5231123")); + ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( + new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) + .setAlgorithmParameterSpec(rsaSpec) + .build()); + + Parcel parcel = parcelForReading(spec); + KeyGenParameterSpec fromParcel = + ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec(); + RSAKeyGenParameterSpec parcelSpec = + (RSAKeyGenParameterSpec) fromParcel.getAlgorithmParameterSpec(); + // Compare individual fields as RSAKeyGenParameterSpec, on android, does not + // implement equals() + assertEquals(parcelSpec.getKeysize(), rsaSpec.getKeysize()); + assertEquals(parcelSpec.getPublicExponent(), rsaSpec.getPublicExponent()); + } + + @Test + public void testParcelingECAlgoParameter() { + ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256"); + ParcelableKeyGenParameterSpec spec = new ParcelableKeyGenParameterSpec( + new KeyGenParameterSpec.Builder(ALIAS, KEY_PURPOSES) + .setAlgorithmParameterSpec(ecSpec) + .build()); + Parcel parcel = parcelForReading(spec); + KeyGenParameterSpec fromParcel = + ParcelableKeyGenParameterSpec.CREATOR.createFromParcel(parcel).getSpec(); + // Compare individual fields as ECGenParameterSpec, on android, does not + // implement equals() + ECGenParameterSpec parcelSpec = (ECGenParameterSpec) fromParcel.getAlgorithmParameterSpec(); + assertEquals(parcelSpec.getName(), ecSpec.getName()); + } +} diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index d41db63aed92..4243e7eeef8c 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -59,6 +59,7 @@ bool Properties::forceDrawFrame = false; bool Properties::filterOutTestOverhead = false; bool Properties::disableVsync = false; bool Properties::skpCaptureEnabled = false; +bool Properties::enableRTAnimations = true; static int property_get_int(const char* key, int defaultValue) { char buf[PROPERTY_VALUE_MAX] = { diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 9c30e4a166f3..af4b694fe86a 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -255,6 +255,9 @@ public: static bool skpCaptureEnabled; + // For experimentation b/68769804 + ANDROID_API static bool enableRTAnimations; + // Used for testing only to change the render pipeline. static void overrideRenderPipelineType(RenderPipelineType); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index b7bb2d15f3b8..820789dd055d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -34,6 +34,7 @@ #include "renderstate/Stencil.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" +#include "../Properties.h" #include <cutils/properties.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -375,6 +376,9 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy } if (info.out.hasAnimations || !info.out.canDrawThisFrame) { + if (CC_UNLIKELY(!Properties::enableRTAnimations)) { + info.out.requiresUiRedraw = true; + } if (!info.out.requiresUiRedraw) { // If animationsNeedsRedraw is set don't bother posting for an RT anim // as we will just end up fighting the UI thread. diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp index a92cbfdf6757..e7496f707318 100644 --- a/libs/hwui/tests/unit/VectorDrawableTests.cpp +++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp @@ -85,32 +85,8 @@ const static TestData sTestDataSet[] = { outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0); outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0); outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0); - outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767, - 22.8911717921705, 16.737515350332117, 24.986664170401575); - outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483, - 28.644011882390082, 11.155893964798905, 29.37447073281729); - outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471, - 29.954422532383525, 4.0686829203897235, 28.951642951534332); - outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696, - 26.161860541657013, -0.9516429515343354, 23.931317079610267); - outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987, - 19.178055668693663, -1.37447073281729, 16.844106035201087); - outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546, - 12.523358440585524, 3.0133358295984305, 11.262484649667876); - outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984, - 9.552224962671648, 10.000000000000005, 10.0); - outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881, - 12.928932188134523, 2.9289321881345254); - outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972, - 4.870079381441987E-16, 19.999999999999996, 0.0); - outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112, - 1.0542876468501678, 27.071067811865476, 2.9289321881345227); - outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0, - 9.999999999999998); - outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112, - 27.071067811865476, 17.071067811865476); - outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0, - 20.000000000000004, 20.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0); }}, // Check box VectorDrawable path data @@ -181,22 +157,7 @@ const static TestData sTestDataSet[] = { }, [](SkPath* outPath) { outPath->moveTo(300.0, 70.0); - outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267, - 94.47383115953485, 137.6004913602211, 137.6302781499585); - outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275, - 239.3163266242308, 70.50013586976587, 300.2494566687817); - outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249, - 419.65954850554147, 137.9538527586204, 462.72238058830936); - outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056, - 529.999456521097, 300.49999999999994, 529.999456521097); - outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176, - 505.78521267107726, 463.0461472413797, 462.7223805883093); - outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891, - 361.1825867133324, 530.4998641302341, 300.2494566687815); - outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844, - 180.7867251403819, 463.3995086397787, 137.6302781499583); - outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255, - 70.13246340443492, 300.9999999999996, 70.00000000000003); + outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0); outPath->close(); outPath->moveTo(300.0, 70.0); }}, diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp index 1931d646fa4a..6b8f3154dd36 100644 --- a/libs/hwui/utils/VectorDrawableUtils.cpp +++ b/libs/hwui/utils/VectorDrawableUtils.cpp @@ -96,132 +96,6 @@ void VectorDrawableUtils::interpolatePaths(PathData* outData, const PathData& fr } } -/** - * Converts an arc to cubic Bezier segments and records them in p. - * - * @param p The target for the cubic Bezier segments - * @param cx The x coordinate center of the ellipse - * @param cy The y coordinate center of the ellipse - * @param a The radius of the ellipse in the horizontal direction - * @param b The radius of the ellipse in the vertical direction - * @param e1x E(eta1) x coordinate of the starting point of the arc - * @param e1y E(eta2) y coordinate of the starting point of the arc - * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane - * @param start The start angle of the arc on the ellipse - * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse - */ -static void arcToBezier(SkPath* p, double cx, double cy, double a, double b, double e1x, double e1y, - double theta, double start, double sweep) { - // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html - // and http://www.spaceroots.org/documents/ellipse/node22.html - - // Maximum of 45 degrees per cubic Bezier segment - int numSegments = ceil(fabs(sweep * 4 / M_PI)); - - double eta1 = start; - double cosTheta = cos(theta); - double sinTheta = sin(theta); - double cosEta1 = cos(eta1); - double sinEta1 = sin(eta1); - double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); - double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); - - double anglePerSegment = sweep / numSegments; - for (int i = 0; i < numSegments; i++) { - double eta2 = eta1 + anglePerSegment; - double sinEta2 = sin(eta2); - double cosEta2 = cos(eta2); - double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); - double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); - double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; - double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; - double tanDiff2 = tan((eta2 - eta1) / 2); - double alpha = sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; - double q1x = e1x + alpha * ep1x; - double q1y = e1y + alpha * ep1y; - double q2x = e2x - alpha * ep2x; - double q2y = e2y - alpha * ep2y; - - p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y); - eta1 = eta2; - e1x = e2x; - e1y = e2y; - ep1x = ep2x; - ep1y = ep2y; - } -} - -inline double toRadians(float theta) { - return theta * M_PI / 180; -} - -static void drawArc(SkPath* p, float x0, float y0, float x1, float y1, float a, float b, - float theta, bool isMoreThanHalf, bool isPositiveArc) { - /* Convert rotation angle from degrees to radians */ - double thetaD = toRadians(theta); - /* Pre-compute rotation matrix entries */ - double cosTheta = cos(thetaD); - double sinTheta = sin(thetaD); - /* Transform (x0, y0) and (x1, y1) into unit space */ - /* using (inverse) rotation, followed by (inverse) scale */ - double x0p = (x0 * cosTheta + y0 * sinTheta) / a; - double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; - double x1p = (x1 * cosTheta + y1 * sinTheta) / a; - double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; - - /* Compute differences and averages */ - double dx = x0p - x1p; - double dy = y0p - y1p; - double xm = (x0p + x1p) / 2; - double ym = (y0p + y1p) / 2; - /* Solve for intersecting unit circles */ - double dsq = dx * dx + dy * dy; - if (dsq == 0.0) { - VECTOR_DRAWABLE_LOGD("Points are coincident"); - return; /* Points are coincident */ - } - double disc = 1.0 / dsq - 1.0 / 4.0; - if (disc < 0.0) { - VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq); - float adjust = (float)(sqrt(dsq) / 1.99999); - drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc); - return; /* Points are too far apart */ - } - double s = sqrt(disc); - double sdx = s * dx; - double sdy = s * dy; - double cx; - double cy; - if (isMoreThanHalf == isPositiveArc) { - cx = xm - sdy; - cy = ym + sdx; - } else { - cx = xm + sdy; - cy = ym - sdx; - } - - double eta0 = atan2((y0p - cy), (x0p - cx)); - - double eta1 = atan2((y1p - cy), (x1p - cx)); - - double sweep = (eta1 - eta0); - if (isPositiveArc != (sweep >= 0)) { - if (sweep > 0) { - sweep -= 2 * M_PI; - } else { - sweep += 2 * M_PI; - } - } - - cx *= a; - cy *= b; - double tcx = cx; - cx = cx * cosTheta - cy * sinTheta; - cy = tcx * sinTheta + cy * cosTheta; - - arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); -} - // Use the given verb, and points in the range [start, end) to insert a command into the SkPath. void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd, const std::vector<float>* points, size_t start, size_t end) { @@ -424,18 +298,20 @@ void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd, break; case 'a': // Draws an elliptical arc // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) - drawArc(outPath, currentX, currentY, points->at(k + 5) + currentX, - points->at(k + 6) + currentY, points->at(k + 0), points->at(k + 1), - points->at(k + 2), points->at(k + 3) != 0, points->at(k + 4) != 0); + outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + (SkPath::ArcSize) (points->at(k + 3) != 0), + (SkPath::Direction) (points->at(k + 4) == 0), + points->at(k + 5) + currentX, points->at(k + 6) + currentY); currentX += points->at(k + 5); currentY += points->at(k + 6); ctrlPointX = currentX; ctrlPointY = currentY; break; case 'A': // Draws an elliptical arc - drawArc(outPath, currentX, currentY, points->at(k + 5), points->at(k + 6), - points->at(k + 0), points->at(k + 1), points->at(k + 2), - points->at(k + 3) != 0, points->at(k + 4) != 0); + outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + (SkPath::ArcSize) (points->at(k + 3) != 0), + (SkPath::Direction) (points->at(k + 4) == 0), + points->at(k + 5), points->at(k + 6)); currentX = points->at(k + 5); currentY = points->at(k + 6); ctrlPointX = currentX; diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk index 73b2bb51a868..44d290e41c16 100644 --- a/location/tests/locationtests/Android.mk +++ b/location/tests/locationtests/Android.mk @@ -7,7 +7,7 @@ LOCAL_MODULE_TAGS := tests # Include all test java files. LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := FrameworksLocationTests LOCAL_STATIC_JAVA_LIBRARIES := \ diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk index bb0a944b5e7d..99499dcb2b66 100644 --- a/lowpan/tests/Android.mk +++ b/lowpan/tests/Android.mk @@ -56,6 +56,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ + android.test.base \ LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index ab0da072047c..21410eac3d8d 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -24,7 +24,6 @@ #define USE_SHARED_MEM_BUFFER #include <media/AudioTrack.h> -#include <media/IMediaHTTPService.h> #include <media/mediaplayer.h> #include "SoundPool.h" #include "SoundPoolThread.h" diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk index 4b6e0e60652b..afc743d84249 100644 --- a/packages/Osu2/tests/Android.mk +++ b/packages/Osu2/tests/Android.mk @@ -20,7 +20,7 @@ LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_JACK_FLAGS := --multi-dex native diff --git a/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml b/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml new file mode 100644 index 000000000000..a0b8155c0818 --- /dev/null +++ b/packages/SettingsLib/res/layout/preference_dropdown_material_settings.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + + +<!-- Based off frameworks/base/core/res/res/layout/preference_dropdown_material.xml + except that icon space in this layout is always reserved --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Spinner + android:id="@+id/spinner" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/preference_no_icon_padding_start" + android:visibility="invisible" /> + + <include layout="@layout/preference_material"/> + +</FrameLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml index d7032b8c4b26..cf9f3c67137c 100644 --- a/packages/SettingsLib/res/values/styles_support_preference.xml +++ b/packages/SettingsLib/res/values/styles_support_preference.xml @@ -20,14 +20,73 @@ <dimen name="preference_no_icon_padding_start">72dp</dimen> + <!-- Fragment style --> + <style name="PreferenceFragmentStyle.SettingsBase" parent="@*android:style/PreferenceFragment.Material"> + <item name="allowDividerAfterLastItem">false</item> + </style> + + <!-- Preferences --> + <style name="Preference.SettingsBase" parent="@style/Preference.Material"> + <item name="allowDividerAbove">false</item> + <item name="allowDividerBelow">true</item> + <item name="singleLineTitle">false</item> + <item name="iconSpaceReserved">true</item> + </style> + + <!-- Preference category --> + <style name="Preference.Category.SettingsBase" parent="@style/Preference.Category.Material"> + <item name="allowDividerAbove">true</item> + <item name="allowDividerBelow">true</item> + <item name="android:layout">@layout/preference_category_material_settings</item> + </style> + + <!-- Preference screen --> + <style name="Preference.Screen.SettingsBase" parent="@style/Preference.PreferenceScreen.Material"> + <item name="allowDividerAbove">false</item> + <item name="allowDividerBelow">true</item> + <item name="iconSpaceReserved">true</item> + </style> + <!-- Footer Preferences --> - <style name="Preference.FooterPreference.SettingsBase" parent="@style/Preference.Material"> + <style name="Preference.FooterPreference.SettingsBase" parent="Preference.SettingsBase"> <item name="android:layout">@layout/preference_footer</item> <item name="allowDividerAbove">true</item> </style> + <!-- Dropdown Preferences --> + <style name="Preference.DropdownPreference.SettingsBase" parent="Preference.SettingsBase"> + <item name="android:layout">@layout/preference_dropdown_material_settings</item> + </style> + + <!-- Switch Preferences --> + <style name="Preference.SwitchPreference.SettingsBase" parent="@style/Preference.SwitchPreference.Material"> + <item name="allowDividerAbove">false</item> + <item name="allowDividerBelow">true</item> + <item name="iconSpaceReserved">true</item> + <item name="singleLineTitle">false</item> + </style> + + <!-- EditText Preferences --> + <style name="Preference.EditTextPreference.SettingsBase" + parent="@style/Preference.DialogPreference.EditTextPreference.Material"> + <item name="allowDividerAbove">false</item> + <item name="allowDividerBelow">true</item> + <item name="iconSpaceReserved">true</item> + <item name="singleLineTitle">false</item> + </style> + <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay.v14.Material"> + <!-- Parent path frameworks/support/v14/preference/res/values/themes.xml --> + <item name="android:scrollbars">vertical</item> + <item name="preferenceFragmentStyle">@style/PreferenceFragmentStyle.SettingsBase</item> + <item name="preferenceCategoryStyle">@style/Preference.Category.SettingsBase</item> + <item name="preferenceScreenStyle">@style/Preference.Screen.SettingsBase</item> + <item name="preferenceStyle">@style/Preference.SettingsBase</item> + <item name="dialogPreferenceStyle">@style/Preference.SettingsBase</item> + <item name="editTextPreferenceStyle">@style/Preference.EditTextPreference.SettingsBase</item> <item name="footerPreferenceStyle">@style/Preference.FooterPreference.SettingsBase</item> + <item name="switchPreferenceStyle">@style/Preference.SwitchPreference.SettingsBase</item> + <item name="dropdownPreferenceStyle">@style/Preference.DropdownPreference.SettingsBase</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 7fb6ede8b29d..f4ec93666490 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -174,13 +174,10 @@ public class SettingsProvider extends ContentProvider { Settings.NameValueTable.VALUE }; - public static final int SETTINGS_TYPE_GLOBAL = 0; - public static final int SETTINGS_TYPE_SYSTEM = 1; - public static final int SETTINGS_TYPE_SECURE = 2; - public static final int SETTINGS_TYPE_SSAID = 3; - - public static final int SETTINGS_TYPE_MASK = 0xF0000000; - public static final int SETTINGS_TYPE_SHIFT = 28; + public static final int SETTINGS_TYPE_GLOBAL = SettingsState.SETTINGS_TYPE_GLOBAL; + public static final int SETTINGS_TYPE_SYSTEM = SettingsState.SETTINGS_TYPE_SYSTEM; + public static final int SETTINGS_TYPE_SECURE = SettingsState.SETTINGS_TYPE_SECURE; + public static final int SETTINGS_TYPE_SSAID = SettingsState.SETTINGS_TYPE_SSAID; private static final Bundle NULL_SETTING_BUNDLE = Bundle.forPair( Settings.NameValueTable.VALUE, null); @@ -278,40 +275,23 @@ public class SettingsProvider extends ContentProvider { private volatile IPackageManager mPackageManager; public static int makeKey(int type, int userId) { - return (type << SETTINGS_TYPE_SHIFT) | userId; + return SettingsState.makeKey(type, userId); } public static int getTypeFromKey(int key) { - return key >>> SETTINGS_TYPE_SHIFT; + return SettingsState.getTypeFromKey(key); } public static int getUserIdFromKey(int key) { - return key & ~SETTINGS_TYPE_MASK; + return SettingsState.getUserIdFromKey(key); } public static String settingTypeToString(int type) { - switch (type) { - case SETTINGS_TYPE_GLOBAL: { - return "SETTINGS_GLOBAL"; - } - case SETTINGS_TYPE_SECURE: { - return "SETTINGS_SECURE"; - } - case SETTINGS_TYPE_SYSTEM: { - return "SETTINGS_SYSTEM"; - } - case SETTINGS_TYPE_SSAID: { - return "SETTINGS_SSAID"; - } - default: { - return "UNKNOWN"; - } - } + return SettingsState.settingTypeToString(type); } public static String keyToString(int key) { - return "Key[user=" + getUserIdFromKey(key) + ";type=" - + settingTypeToString(getTypeFromKey(key)) + "]"; + return SettingsState.keyToString(key); } @Override diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index f901bcaee69e..a8a67abaf8ae 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -33,6 +33,7 @@ import android.os.Message; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.Global; import android.providers.settings.GlobalSettingsProto; import android.providers.settings.SettingsOperationProto; import android.text.TextUtils; @@ -46,6 +47,7 @@ import android.util.Xml; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import libcore.io.IoUtils; @@ -195,6 +197,51 @@ final class SettingsState { @GuardedBy("mLock") private int mNextHistoricalOpIdx; + public static final int SETTINGS_TYPE_GLOBAL = 0; + public static final int SETTINGS_TYPE_SYSTEM = 1; + public static final int SETTINGS_TYPE_SECURE = 2; + public static final int SETTINGS_TYPE_SSAID = 3; + + public static final int SETTINGS_TYPE_MASK = 0xF0000000; + public static final int SETTINGS_TYPE_SHIFT = 28; + + public static int makeKey(int type, int userId) { + return (type << SETTINGS_TYPE_SHIFT) | userId; + } + + public static int getTypeFromKey(int key) { + return key >>> SETTINGS_TYPE_SHIFT; + } + + public static int getUserIdFromKey(int key) { + return key & ~SETTINGS_TYPE_MASK; + } + + public static String settingTypeToString(int type) { + switch (type) { + case SETTINGS_TYPE_GLOBAL: { + return "SETTINGS_GLOBAL"; + } + case SETTINGS_TYPE_SECURE: { + return "SETTINGS_SECURE"; + } + case SETTINGS_TYPE_SYSTEM: { + return "SETTINGS_SYSTEM"; + } + case SETTINGS_TYPE_SSAID: { + return "SETTINGS_SSAID"; + } + default: { + return "UNKNOWN"; + } + } + } + + public static String keyToString(int key) { + return "Key[user=" + getUserIdFromKey(key) + ";type=" + + settingTypeToString(getTypeFromKey(key)) + "]"; + } + public SettingsState(Context context, Object lock, File file, int key, int maxBytesPerAppPackage, Looper looper) { // It is important that we use the same lock as the settings provider @@ -604,6 +651,13 @@ final class SettingsState { for (int i = 0; i < settingCount; i++) { Setting setting = settings.valueAt(i); + if (setting.isTransient()) { + if (DEBUG_PERSISTENCE) { + Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName()); + } + continue; + } + writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(), setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), setting.getTag(), setting.isDefaultFromSystem()); @@ -914,6 +968,14 @@ final class SettingsState { return update(this.defaultValue, false, packageName, null, true); } + public boolean isTransient() { + switch (getTypeFromKey(getKey())) { + case SETTINGS_TYPE_GLOBAL: + return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName()); + } + return false; + } + public boolean update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage) { if (NULL_VALUE.equals(value)) { diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk index a9707d4ae69b..902f1c7ed388 100644 --- a/packages/SettingsProvider/test/Android.mk +++ b/packages/SettingsProvider/test/Android.mk @@ -12,7 +12,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \ LOCAL_STATIC_JAVA_LIBRARIES := android-support-test -LOCAL_JAVA_LIBRARIES := legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.base LOCAL_PACKAGE_NAME := SettingsProviderTest diff --git a/packages/SystemUI/res/drawable/instant_icon.xml b/packages/SystemUI/res/drawable/instant_icon.xml index 0039c8111f12..8554daa05078 100644 --- a/packages/SystemUI/res/drawable/instant_icon.xml +++ b/packages/SystemUI/res/drawable/instant_icon.xml @@ -14,17 +14,13 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="40dp" - android:height="40dp" - android:viewportWidth="2.2" - android:viewportHeight="2.2"> + android:height="24dp" + android:width="24dp" + android:viewportHeight="48" + android:viewportWidth="48"> <path android:fillColor="#FFFFFFFF" - android:pathData="M.1,1.1 - c0,.55 .45,1 1,1 - c.55,0 1,-.45 1,-1 - c0,-.55 -.45,-1 -1,-1 - c-.55,0 -1,.45 -1,1z - M1.15,.95 l.5,0 l-.7,1 l0.1,-.7 l-.5,0 l.7,-1 z"/> -</vector> + android:pathData="M35.8,18.9l-9.8,0.1l0.2,-19l-14.1,29.3l9.9,0l0,18.7z" /> + +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 775b9e8a4d3b..a980413922ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -16,8 +16,8 @@ package com.android.keyguard; -import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL; -import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; import android.content.Context; import android.os.AsyncTask; @@ -29,6 +29,7 @@ import android.view.KeyEvent; import android.view.View; import android.widget.LinearLayout; +import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index ec5f356a1a55..d636316dfe96 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -15,8 +15,8 @@ */ package com.android.keyguard; -import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL; -import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL; +import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED; import android.content.Context; import android.graphics.Rect; @@ -33,6 +33,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.LinearLayout; +import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java index 0219db332eaf..12f75bb2d56c 100644 --- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java +++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java @@ -307,9 +307,8 @@ public class PasswordTextView extends View { void sendAccessibilityEventTypeViewTextChanged(String beforeText, int fromIndex, int removedCount, int addedCount) { - if (AccessibilityManager.getInstance(mContext).isObservedEventType( - AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) - && (isFocused() || isSelected() && isShown())) { + if (AccessibilityManager.getInstance(mContext).isEnabled() && + (isFocused() || isSelected() && isShown())) { AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); event.setFromIndex(fromIndex); diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags index d4149ea6d68f..9c847be75fab 100644 --- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags +++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags @@ -61,8 +61,3 @@ option java_package com.android.systemui; ## 4: SYSTEM_REGISTER_USER System sysui registers user's callbacks ## 5: SYSTEM_UNREGISTER_USER System sysui unregisters user's callbacks (after death) 36060 sysui_recents_connection (type|1),(user|1) - -# --------------------------- -# LatencyTracker.java -# --------------------------- -36070 sysui_latency (action|1|5),(latency|1|3) diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java index 1d55ee5ac0d6..cbb69ee98a03 100644 --- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java +++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java @@ -25,7 +25,7 @@ import android.os.PowerManager; import android.os.SystemClock; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.systemui.statusbar.phone.FingerprintUnlockController; import com.android.systemui.statusbar.phone.StatusBar; diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java index debda2109637..cc2244a4e934 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java @@ -30,8 +30,6 @@ import android.util.Log; import com.android.systemui.R; -import java.util.Arrays; - /** * Class to store the policy for AOD, which comes from * {@link android.provider.Settings.Global} @@ -102,20 +100,6 @@ public class AlwaysOnDisplayPolicy { mSettingsObserver.observe(); } - private int[] parseIntArray(final String key, final int[] defaultArray) { - final String value = mParser.getString(key, null); - if (value != null) { - try { - return Arrays.stream(value.split(":")).map(String::trim).mapToInt( - Integer::parseInt).toArray(); - } catch (NumberFormatException e) { - return defaultArray; - } - } else { - return defaultArray; - } - } - private final class SettingsObserver extends ContentObserver { private final Uri ALWAYS_ON_DISPLAY_CONSTANTS_URI = Settings.Global.getUriFor(Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS); @@ -154,10 +138,10 @@ public class AlwaysOnDisplayPolicy { DEFAULT_PROX_COOLDOWN_TRIGGER_MS); proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS, DEFAULT_PROX_COOLDOWN_PERIOD_MS); - screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY, + screenBrightnessArray = mParser.getIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY, resources.getIntArray( R.array.config_doze_brightness_sensor_to_brightness)); - dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY, + dimmingScrimArray = mParser.getIntArray(KEY_DIMMING_SCRIM_ARRAY, resources.getIntArray( R.array.config_doze_brightness_sensor_to_scrim_opacity)); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c92acd068745..1faf981f8a83 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -25,7 +25,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT; -import android.app.Activity; + import android.app.ActivityManager; import android.app.AlarmManager; import android.app.NotificationManager; @@ -53,7 +53,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.provider.Settings.System; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.EventLog; @@ -77,20 +76,16 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.Dependency; import com.android.systemui.SystemUI; import com.android.systemui.SystemUIFactory; import com.android.systemui.UiOffloadThread; import com.android.systemui.classifier.FalsingManager; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.phone.FingerprintUnlockController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.StatusBarWindowManager; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 51175d1d7cf0..2b48e0fb32bd 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -387,9 +387,7 @@ public class PipTouchHandler { } case MotionEvent.ACTION_HOVER_ENTER: case MotionEvent.ACTION_HOVER_MOVE: { - if (mAccessibilityManager.isObservedEventType( - AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) - && !mSendingHoverAccessibilityEvents) { + if (mAccessibilityManager.isEnabled() && !mSendingHoverAccessibilityEvents) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); event.setImportantForAccessibility(true); @@ -402,9 +400,7 @@ public class PipTouchHandler { break; } case MotionEvent.ACTION_HOVER_EXIT: { - if (mAccessibilityManager.isObservedEventType( - AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) - && mSendingHoverAccessibilityEvents) { + if (mAccessibilityManager.isEnabled() && mSendingHoverAccessibilityEvents) { AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); event.setImportantForAccessibility(true); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 9aecc686d8aa..ca9a5533db28 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -46,7 +46,7 @@ import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.content.PackageMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index b7a00ebcca41..75321fd7e68f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -82,9 +82,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private boolean mNoAnimationsInThisFrame; private boolean mAnimationsEnabled = true; private boolean mShowNotificationShelf; - private boolean mVibrationOnAnimation; - private boolean mUserTouchingScreen; - private boolean mTouchActive; private float mFirstElementRoundness; public NotificationShelf(Context context, AttributeSet attrs) { @@ -102,9 +99,6 @@ public class NotificationShelf extends ActivatableNotificationView implements setClipChildren(false); setClipToPadding(false); mShelfIcons.setShowAllIcons(false); - mVibrationOnAnimation = mContext.getResources().getBoolean( - R.bool.config_vibrateOnIconAnimation); - updateVibrationOnAnimation(); mViewInvertHelper = new ViewInvertHelper(mShelfIcons, NotificationPanelView.DOZE_ANIMATION_DURATION); mShelfState = new ShelfState(); @@ -112,15 +106,6 @@ public class NotificationShelf extends ActivatableNotificationView implements initDimens(); } - private void updateVibrationOnAnimation() { - mShelfIcons.setVibrateOnAnimation(mVibrationOnAnimation && mTouchActive); - } - - public void setTouchActive(boolean touchActive) { - mTouchActive = touchActive; - updateVibrationOnAnimation(); - } - public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) { mAmbientState = ambientState; mHostLayout = hostLayout; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java index 492ab44d499b..aea0127764b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar; */ import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; @@ -234,7 +233,7 @@ public class NotificationSnooze extends LinearLayout final int defaultSnooze = mParser.getInt(KEY_DEFAULT_SNOOZE, resources.getInteger(R.integer.config_notification_snooze_time_default)); - final int[] snoozeTimes = parseIntArray(KEY_OPTIONS, + final int[] snoozeTimes = mParser.getIntArray(KEY_OPTIONS, resources.getIntArray(R.array.config_notification_snooze_times)); for (int i = 0; i < snoozeTimes.length && i < sAccessibilityActions.length; i++) { @@ -248,21 +247,6 @@ public class NotificationSnooze extends LinearLayout return options; } - @VisibleForTesting - int[] parseIntArray(final String key, final int[] defaultArray) { - final String value = mParser.getString(key, null); - if (value != null) { - try { - return Arrays.stream(value.split(":")).map(String::trim).mapToInt( - Integer::parseInt).toArray(); - } catch (NumberFormatException e) { - return defaultArray; - } - } else { - return defaultArray; - } - } - private SnoozeOption createOption(int minutes, int accessibilityActionId) { Resources res = getResources(); boolean showInHours = minutes >= 60; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java index af393c91730f..7e2336c4454b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java @@ -61,11 +61,6 @@ public class NotificationUtils { return sLocationOffset[1] - sLocationBase[1]; } - public static boolean isHapticFeedbackDisabled(Context context) { - return Settings.System.getIntForUser(context.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - } - /** * @param dimenId the dimen to look up * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index 80d4061b3864..a2b1013167de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -26,7 +26,7 @@ import android.util.Log; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.systemui.Dependency; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; @@ -266,7 +266,6 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { } private void showBouncer() { - mScrimController.transitionTo(ScrimState.BOUNCER); mStatusBarKeyguardViewManager.animateCollapsePanels( FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); mPendingShowBouncer = false; 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 6d3bc1df00a2..61b007f42551 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -67,7 +67,7 @@ import android.view.accessibility.AccessibilityManager.AccessibilityServicesStat import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 836efffbd4e4..a1b49c15a560 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled; - import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; @@ -120,8 +118,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private float mVisualOverflowAdaption; private boolean mDisallowNextAnimation; private boolean mAnimationsEnabled = true; - private boolean mVibrateOnAnimation; - private Vibrator mVibrator; private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons; private int mDarkOffsetX; @@ -129,7 +125,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { super(context, attrs); initDimens(); setWillNotDraw(!DEBUG); - mVibrator = mContext.getSystemService(Vibrator.class); } private void initDimens() { @@ -497,10 +492,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { return width - (getWidth() - getActualPaddingStart() - getActualPaddingEnd()) > 0; } - public void setVibrateOnAnimation(boolean vibrateOnAnimation) { - mVibrateOnAnimation = vibrateOnAnimation; - } - public int getIconSize() { return mIconSize; } @@ -608,39 +599,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } else { super.applyToView(view); } - boolean wasInShelf = icon.isInShelf(); boolean inShelf = iconAppearAmount == 1.0f; icon.setIsInShelf(inShelf); - if (shouldVibrateChange(wasInShelf != inShelf)) { - AsyncTask.execute( - () -> mVibrator.vibrate(VibrationEffect.get( - VibrationEffect.EFFECT_TICK))); - } } justAdded = false; justReplaced = false; needsCannedAnimation = false; } - private boolean shouldVibrateChange(boolean inShelfChanged) { - if (!mVibrateOnAnimation) { - return false; - } - if (justAdded) { - return false; - } - if (!mAnimationsEnabled) { - return false; - } - if (!inShelfChanged) { - return false; - } - if (isHapticFeedbackDisabled(mContext)) { - return false; - } - return true; - } - public boolean hasCustomTransformHeight() { return isLastExpandIcon && customTransformHeight != NO_VALUE; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index afe5c917a856..2fc22caa6c05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.phone; -import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -25,7 +23,9 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.database.ContentObserver; import android.os.AsyncTask; +import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; import android.os.VibrationEffect; @@ -42,7 +42,7 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -50,7 +50,6 @@ import com.android.systemui.classifier.FalsingManager; import com.android.systemui.doze.DozeLog; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.policy.HeadsUpManager; import java.io.FileDescriptor; @@ -66,6 +65,7 @@ public abstract class PanelView extends FrameLayout { private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); private boolean mPanelUpdateWhenAnimatorEnds; private boolean mVibrateOnOpening; + private boolean mVibrationEnabled; private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); @@ -108,6 +108,12 @@ public abstract class PanelView extends FrameLayout { private FlingAnimationUtils mFlingAnimationUtilsDismissing; private FalsingManager mFalsingManager; private final Vibrator mVibrator; + final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) { + @Override + public void onChange(boolean selfChange) { + updateHapticFeedBackEnabled(); + } + }; /** * Whether an instant expand request is currently pending and we are just waiting for layout. @@ -212,6 +218,15 @@ public abstract class PanelView extends FrameLayout { mVibrator = mContext.getSystemService(Vibrator.class); mVibrateOnOpening = mContext.getResources().getBoolean( R.bool.config_vibrateOnIconAnimation); + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true, + mVibrationObserver); + mVibrationObserver.onChange(false /* selfChange */); + } + + public void updateHapticFeedBackEnabled() { + mVibrationEnabled = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0; } protected void loadDimens() { @@ -403,7 +418,7 @@ public abstract class PanelView extends FrameLayout { runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(), false /* collapseWhenFinished */); notifyBarPanelExpansionChanged(); - if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) { + if (mVibrateOnOpening && mVibrationEnabled) { AsyncTask.execute(() -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false))); } 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 7c334375d47e..59533e602ae1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -649,15 +649,6 @@ public class StatusBar extends SystemUI implements DemoMode, .Callback() { @Override public void onFinished() { - notifyKeyguardState(); - } - - @Override - public void onCancelled() { - notifyKeyguardState(); - } - - private void notifyKeyguardState() { if (mStatusBarKeyguardViewManager == null) { Log.w(TAG, "Tried to notify keyguard visibility when " + "mStatusBarKeyguardViewManager was null"); @@ -665,6 +656,12 @@ public class StatusBar extends SystemUI implements DemoMode, } mStatusBarKeyguardViewManager.onKeyguardFadedAway(); } + + @Override + public void onCancelled() { + // Transition was cancelled because another one took over. + // Nothing to do in here but wait. + } }; private NotificationMessagingUtil mMessagingUtil; @@ -5112,6 +5109,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void notifyFpAuthModeChanged() { updateDozing(); + updateScrimController(); } private void updateDozing() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index ef05bbb4fe3d..dacd3d935d0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -33,7 +33,7 @@ import android.view.WindowManagerGlobal; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.keyguard.LatencyTracker; +import com.android.internal.util.LatencyTracker; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index d7f11f710501..4accd86cce98 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -248,7 +248,6 @@ public class StatusBarWindowView extends FrameLayout { public void setTouchActive(boolean touchActive) { mTouchActive = touchActive; - mStackScrollLayout.setTouchActive(touchActive); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index a3d2423f5df1..0f2a2c8b2bc2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -4443,10 +4443,6 @@ public class NotificationStackScrollLayout extends ViewGroup mAmbientState.getScrollY())); } - public void setTouchActive(boolean touchActive) { - mShelf.setTouchActive(touchActive); - } - /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java index 6b31c967a247..756bb1c104ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationSnoozeTest.java @@ -62,57 +62,6 @@ public class NotificationSnoozeTest extends SysuiTestCase { } @Test - public void testParseIntArrayNull() throws Exception { - when(mMockParser.getString(anyString(), isNull())).thenReturn(null); - mNotificationSnooze.setKeyValueListParser(mMockParser); - - int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS); - assertEquals(RES_OPTIONS, result); - } - - @Test - public void testParseIntArrayLeadingSep() throws Exception { - when(mMockParser.getString(anyString(), isNull())).thenReturn(":4:5:6"); - mNotificationSnooze.setKeyValueListParser(mMockParser); - - int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS); - assertEquals(RES_OPTIONS, result); - } - - @Test - public void testParseIntArrayEmptyItem() throws Exception { - when(mMockParser.getString(anyString(), isNull())).thenReturn("4::6"); - mNotificationSnooze.setKeyValueListParser(mMockParser); - - int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS); - assertEquals(RES_OPTIONS, result); - } - - @Test - public void testParseIntArrayTrailingSep() throws Exception { - when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6:"); - mNotificationSnooze.setKeyValueListParser(mMockParser); - - int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS); - assertEquals(3, result.length); - assertEquals(4, result[0]); // respect order - assertEquals(5, result[1]); - assertEquals(6, result[2]); - } - - @Test - public void testParseIntArrayGoodData() throws Exception { - when(mMockParser.getString(anyString(), isNull())).thenReturn("4:5:6"); - mNotificationSnooze.setKeyValueListParser(mMockParser); - - int[] result = mNotificationSnooze.parseIntArray("foo", RES_OPTIONS); - assertEquals(3, result.length); - assertEquals(4, result[0]); // respect order - assertEquals(5, result[1]); - assertEquals(6, result[2]); - } - - @Test public void testGetOptionsWithNoConfig() throws Exception { ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); assertEquals(3, result.size()); 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 713f7843eaea..0aeb7b6bf34c 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 @@ -104,6 +104,7 @@ public class StatusBarTest extends SysuiTestCase { PowerManager mPowerManager; SystemServicesProxy mSystemServicesProxy; NotificationPanelView mNotificationPanelView; + ScrimController mScrimController; IStatusBarService mBarService; ArrayList<Entry> mNotificationList; private DisplayMetrics mDisplayMetrics = new DisplayMetrics(); @@ -131,6 +132,7 @@ public class StatusBarTest extends SysuiTestCase { mNotificationPanelView = mock(NotificationPanelView.class); when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); mNotificationList = mock(ArrayList.class); + mScrimController = mock(ScrimController.class); IPowerManager powerManagerService = mock(IPowerManager.class); HandlerThread handlerThread = new HandlerThread("TestThread"); handlerThread.start(); @@ -143,7 +145,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache, mKeyguardIndicationController, mStackScroller, mHeadsUpManager, mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView, - mBarService); + mBarService, mScrimController); mStatusBar.mContext = mContext; mStatusBar.mComponents = mContext.getComponents(); doAnswer(invocation -> { @@ -532,12 +534,21 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.updateKeyguardState(false, false); } + @Test + public void testFingerprintNotification_UpdatesScrims() { + mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class); + mStatusBar.mFingerprintUnlockController = mock(FingerprintUnlockController.class); + mStatusBar.mDozeScrimController = mock(DozeScrimController.class); + mStatusBar.notifyFpAuthModeChanged(); + verify(mScrimController).transitionTo(any(), any()); + } + static class TestableStatusBar extends StatusBar { public TestableStatusBar(StatusBarKeyguardViewManager man, UnlockMethodCache unlock, KeyguardIndicationController key, NotificationStackScrollLayout stack, HeadsUpManager hum, NotificationData nd, PowerManager pm, SystemServicesProxy ssp, NotificationPanelView panelView, - IStatusBarService barService) { + IStatusBarService barService, ScrimController scrimController) { mStatusBarKeyguardViewManager = man; mUnlockMethodCache = unlock; mKeyguardIndicationController = key; @@ -550,7 +561,7 @@ public class StatusBarTest extends SysuiTestCase { mNotificationPanel = panelView; mBarService = barService; mWakefulnessLifecycle = createAwakeWakefulnessLifecycle(); - mScrimController = mock(ScrimController.class); + mScrimController = scrimController; } private WakefulnessLifecycle createAwakeWakefulnessLifecycle() { diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 968e08b00663..6faf1f9dcd71 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5028,8 +5028,33 @@ message MetricsEvent { // OS: P SCREEN_LOCK_SETTINGS = 1265; - // ---- End P Constants, all P constants go above this line ---- + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon) + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267; + + // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_TOGGLE_DND_BUTTON = 1268; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269; + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270; + + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/Android.bp b/services/Android.bp new file mode 100644 index 000000000000..84c45fe7f6bd --- /dev/null +++ b/services/Android.bp @@ -0,0 +1,8 @@ +// native library +// ============================================================= + +cc_library_shared { + name: "libandroid_servers", + defaults: ["libservices.core-libs"], + whole_static_libs: ["libservices.core"], +} diff --git a/services/Android.mk b/services/Android.mk index ed2ba1f81939..81d8181077b8 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -52,23 +52,6 @@ endif include $(BUILD_JAVA_LIBRARY) -# native library -# ============================================================= - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := -LOCAL_SHARED_LIBRARIES := - -# include all the jni subdirs to collect their sources -include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk) - -LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES - -LOCAL_MODULE:= libandroid_servers - -include $(BUILD_SHARED_LIBRARY) - # ============================================================= ifeq (,$(ONE_SHOT_MAKEFILE)) diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java index 22d922be11af..7e94d7b6f1fe 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityClientConnection.java @@ -20,7 +20,9 @@ import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; +import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; +import android.accessibilityservice.GestureDescription; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; @@ -47,6 +49,7 @@ import android.view.MagnificationSpec; import android.view.View; import android.view.accessibility.AccessibilityCache; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; @@ -62,7 +65,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -104,7 +106,7 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec int mFeedbackType; - final Set<String> mPackageNames = new HashSet<>(); + Set<String> mPackageNames = new HashSet<>(); boolean mIsDefault; @@ -282,98 +284,40 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec return true; } - boolean setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { - boolean somethingChanged = false; - - if (mEventTypes != info.eventTypes) { - mEventTypes = info.eventTypes; - somethingChanged = true; - } - - if (mFeedbackType != info.feedbackType) { - mFeedbackType = info.feedbackType; - somethingChanged = true; + public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { + mEventTypes = info.eventTypes; + mFeedbackType = info.feedbackType; + String[] packageNames = info.packageNames; + if (packageNames != null) { + mPackageNames.addAll(Arrays.asList(packageNames)); } + mNotificationTimeout = info.notificationTimeout; + mIsDefault = (info.flags & DEFAULT) != 0; - final String[] oldPackageNames = mPackageNames.toArray(new String[mPackageNames.size()]); - if (!Arrays.equals(oldPackageNames, info.packageNames)) { - mPackageNames.clear(); - if (info.packageNames != null) { - Collections.addAll(mPackageNames, info.packageNames); + if (supportsFlagForNotImportantViews(info)) { + if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { + mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; + } else { + mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; } - somethingChanged = true; - } - - if (mNotificationTimeout != info.notificationTimeout) { - mNotificationTimeout = info.notificationTimeout; - somethingChanged = true; } - final boolean newIsDefault = (info.flags & DEFAULT) != 0; - if (mIsDefault != newIsDefault) { - mIsDefault = newIsDefault; - somethingChanged = true; - } - - if (supportsFlagForNotImportantViews(info)) { - somethingChanged |= updateFetchFlag(info.flags, - AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS); + if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { + mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; + } else { + mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; } - somethingChanged |= updateFetchFlag(info.flags, - AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS); - - final boolean newRequestTouchExplorationMode = (info.flags + mRequestTouchExplorationMode = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; - if (mRequestTouchExplorationMode != newRequestTouchExplorationMode) { - mRequestTouchExplorationMode = newRequestTouchExplorationMode; - somethingChanged = true; - } - - final boolean newRequestFilterKeyEvents = (info.flags + mRequestFilterKeyEvents = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; - if (mRequestFilterKeyEvents != newRequestFilterKeyEvents) { - mRequestFilterKeyEvents = newRequestFilterKeyEvents; - somethingChanged = true; - } - - final boolean newRetrieveInteractiveWindows = (info.flags + mRetrieveInteractiveWindows = (info.flags & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; - if (mRetrieveInteractiveWindows != newRetrieveInteractiveWindows) { - mRetrieveInteractiveWindows = newRetrieveInteractiveWindows; - somethingChanged = true; - } - - final boolean newCaptureFingerprintGestures = (info.flags + mCaptureFingerprintGestures = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0; - if (mCaptureFingerprintGestures != newCaptureFingerprintGestures) { - mCaptureFingerprintGestures = newCaptureFingerprintGestures; - somethingChanged = true; - } - - final boolean newRequestAccessibilityButton = (info.flags + mRequestAccessibilityButton = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; - if (mRequestAccessibilityButton != newRequestAccessibilityButton) { - mRequestAccessibilityButton = newRequestAccessibilityButton; - somethingChanged = true; - } - - return somethingChanged; - } - - private boolean updateFetchFlag(int allFlags, int flagToUpdate) { - if ((allFlags & flagToUpdate) != 0) { - if ((mFetchFlags & flagToUpdate) == 0) { - mFetchFlags |= flagToUpdate; - return true; - } - } else { - if ((mFetchFlags & flagToUpdate) != 0) { - mFetchFlags &= ~flagToUpdate; - return true; - } - } - return false; } protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { @@ -405,15 +349,14 @@ abstract class AccessibilityClientConnection extends IAccessibilityServiceConnec // If the XML manifest had data to configure the service its info // should be already set. In such a case update only the dynamically // configurable properties. - final boolean serviceInfoChanged; AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; if (oldInfo != null) { oldInfo.updateDynamicallyConfigurableProperties(info); - serviceInfoChanged = setDynamicallyConfigurableProperties(oldInfo); + setDynamicallyConfigurableProperties(oldInfo); } else { - serviceInfoChanged = setDynamicallyConfigurableProperties(info); + setDynamicallyConfigurableProperties(info); } - mSystemSupport.onClientChange(serviceInfoChanged); + mSystemSupport.onClientChange(true); } } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8b5c85a72d7a..0a21b9e27862 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -100,7 +100,8 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.util.DumpUtils; import com.android.internal.util.IntPair; import com.android.server.LocalServices; -import com.android.server.policy.AccessibilityShortcutController; +import com.android.internal.accessibility.AccessibilityShortcutController; +import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo; import com.android.server.wm.WindowManagerInternal; import org.xmlpull.v1.XmlPullParserException; @@ -1897,8 +1898,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.mServiceToEnableWithShortcut == null) { return; } - boolean shortcutServiceIsInstalled = false; - for (int i = 0; i < userState.mInstalledServices.size(); i++) { + boolean shortcutServiceIsInstalled = + AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() + .containsKey(userState.mServiceToEnableWithShortcut); + for (int i = 0; !shortcutServiceIsInstalled && (i < userState.mInstalledServices.size()); + i++) { if (userState.mInstalledServices.get(i).getComponentName() .equals(userState.mServiceToEnableWithShortcut)) { shortcutServiceIsInstalled = true; @@ -1909,7 +1913,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId); + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, + userState.mUserId); Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId); @@ -2117,12 +2122,26 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub throw new SecurityException( "performAccessibilityShortcut requires the WRITE_SECURE_SETTINGS permission"); } + final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap = + AccessibilityShortcutController.getFrameworkShortcutFeaturesMap(); synchronized(mLock) { - UserState userState = getUserStateLocked(mCurrentUserId); - ComponentName serviceName = userState.mServiceToEnableWithShortcut; + final UserState userState = getUserStateLocked(mCurrentUserId); + final ComponentName serviceName = userState.mServiceToEnableWithShortcut; if (serviceName == null) { return; } + if (frameworkFeatureMap.containsKey(serviceName)) { + // Toggle the requested framework feature + ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(serviceName); + SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(), + featureInfo.getSettingKey(), mCurrentUserId); + // Assuming that the default state will be to have the feature off + if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) { + setting.write(featureInfo.getSettingOnValue()); + } else { + setting.write(featureInfo.getSettingOffValue()); + } + } final long identity = Binder.clearCallingIdentity(); try { if (userState.mComponentNameToServiceMap.get(serviceName) == null) { @@ -2400,8 +2419,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void announceNewUserIfNeeded() { synchronized (mLock) { UserState userState = getCurrentUserStateLocked(); - if (userState.isHandlingAccessibilityEvents() - && userState.isObservedEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT)) { + if (userState.isHandlingAccessibilityEvents()) { UserManager userManager = (UserManager) mContext.getSystemService( Context.USER_SERVICE); String message = mContext.getString(R.string.user_switched, @@ -3158,21 +3176,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mWindowsForAccessibilityCallback == null) { return; } - final int userId; - synchronized (mLock) { - userId = mCurrentUserId; - final UserState userState = getUserStateLocked(userId); - if (!userState.isObservedEventType(AccessibilityEvent.TYPE_WINDOWS_CHANGED)) { - return; - } - } final long identity = Binder.clearCallingIdentity(); try { // Let the client know the windows changed. AccessibilityEvent event = AccessibilityEvent.obtain( AccessibilityEvent.TYPE_WINDOWS_CHANGED); event.setEventTime(SystemClock.uptimeMillis()); - sendAccessibilityEvent(event, userId); + sendAccessibilityEvent(event, mCurrentUserId); } finally { Binder.restoreCallingIdentity(identity); } @@ -3377,10 +3387,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mUserId = userId; } - public boolean isObservedEventType(@AccessibilityEvent.EventType int type) { - return (mLastSentRelevantEventTypes & type) != 0; - } - public int getClientState() { int clientState = 0; final boolean a11yEnabled = (mUiAutomationManager.isUiAutomationRunningLocked() diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index 62017e879584..3419b809f1b8 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -791,7 +791,7 @@ class TouchExplorer extends BaseEventStreamTransformation */ private void sendAccessibilityEvent(int type) { AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext); - if (accessibilityManager.isObservedEventType(type)) { + if (accessibilityManager.isEnabled()) { AccessibilityEvent event = AccessibilityEvent.obtain(type); event.setWindowId(mAms.getActiveWindowId()); accessibilityManager.sendAccessibilityEvent(event); diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 6c154389526f..b446209790ad 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -2506,6 +2506,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku info.widgetCategory = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); + info.widgetFeatures = sa.getInt( + com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0); sa.recycle(); } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 02912763509f..690c45b06149 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -610,6 +610,21 @@ public final class AutofillManagerService extends SystemService { } @Override + public boolean isFieldClassificationEnabled() throws RemoteException { + UserHandle user = getCallingUserHandle(); + int uid = getCallingUid(); + + synchronized (mLock) { + AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier()); + if (service != null) { + return service.isFieldClassificationEnabled(); + } + } + + return false; + } + + @Override public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback) throws RemoteException { activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 8b6dc2028b91..3ef450a70729 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -47,6 +47,7 @@ import android.os.UserManager; import android.provider.Settings; import android.service.autofill.AutofillService; import android.service.autofill.AutofillServiceInfo; +import android.service.autofill.FieldClassification.Match; import android.service.autofill.FillEventHistory; import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillResponse; @@ -74,6 +75,7 @@ import com.android.server.autofill.ui.AutoFillUI; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Random; /** @@ -626,7 +628,7 @@ final class AutofillManagerServiceImpl { if (isValidEventLocked("setAuthenticationSelected()", sessionId)) { mEventHistory.addEvent( new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null, - null, null, null, null, null, -1)); + null, null, null, null, null, null)); } } } @@ -640,7 +642,7 @@ final class AutofillManagerServiceImpl { if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) { mEventHistory.addEvent( new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset, - clientState, null, null, null, null, null, null, null, -1)); + clientState, null, null, null, null, null, null, null, null)); } } } @@ -652,7 +654,7 @@ final class AutofillManagerServiceImpl { synchronized (mLock) { if (isValidEventLocked("logSaveShown()", sessionId)) { mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null, - null, null, null, null, null, null, -1)); + null, null, null, null, null, null, null)); } } } @@ -666,7 +668,7 @@ final class AutofillManagerServiceImpl { if (isValidEventLocked("logDatasetSelected()", sessionId)) { mEventHistory.addEvent( new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null, - null, null, null, null, null, null, -1)); + null, null, null, null, null, null, null)); } } } @@ -681,14 +683,24 @@ final class AutofillManagerServiceImpl { @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, - @Nullable String detectedRemoteId, int detectedFieldScore) { + @NonNull ArrayList<AutofillId> detectedFieldIdsList, + @NonNull ArrayList<Match> detectedMatchesList) { + synchronized (mLock) { if (isValidEventLocked("logDatasetNotSelected()", sessionId)) { + AutofillId[] detectedFieldsIds = null; + Match[] detectedMatches = null; + if (!detectedFieldIdsList.isEmpty()) { + detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()]; + detectedFieldIdsList.toArray(detectedFieldsIds); + detectedMatches = new Match[detectedMatchesList.size()]; + detectedMatchesList.toArray(detectedMatches); + } mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null, clientState, selectedDatasets, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds, - detectedRemoteId, detectedFieldScore)); + detectedFieldsIds, detectedMatches)); } } } @@ -757,7 +769,8 @@ final class AutofillManagerServiceImpl { pw.print(prefix); pw.print("Default component: "); pw.println(mContext.getString(R.string.config_defaultAutofillService)); pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); - pw.print(prefix); pw.print("Field detection: "); pw.println(isFieldDetectionEnabled()); + pw.print(prefix); pw.print("Field classification enabled: "); + pw.println(isFieldClassificationEnabled()); pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); @@ -1014,10 +1027,10 @@ final class AutofillManagerServiceImpl { return false; } - // TODO(b/67867469): remove once feature is finished - boolean isFieldDetectionEnabled() { + boolean isFieldClassificationEnabled() { return Settings.Secure.getIntForUser( - mContext.getContentResolver(), Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION, 0, + mContext.getContentResolver(), + Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 0, mUserId) == 1; } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 3615bca48e35..dea6669bb7e8 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -55,6 +55,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.AutofillService; import android.service.autofill.Dataset; +import android.service.autofill.FieldClassification.Match; import android.service.autofill.FillContext; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; @@ -64,6 +65,7 @@ import android.service.autofill.SaveInfo; import android.service.autofill.SaveRequest; import android.service.autofill.UserData; import android.service.autofill.ValueFinder; +import android.service.autofill.EditDistanceScorer; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LocalLog; @@ -499,7 +501,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } // TODO(b/67867469): remove once feature is finished - if (response.getFieldClassificationIds() != null && !mService.isFieldDetectionEnabled()) { + if (response.getFieldClassificationIds() != null && !mService.isFieldClassificationEnabled()) { Slog.w(TAG, "Ignoring " + response + " because field detection is disabled"); processNullResponseLocked(requestFlags); return; @@ -942,20 +944,19 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final UserData userData = mService.getUserData(); - final AutofillId detectableFieldId; - final String detectableRemoteId; - String detectedRemoteId = null; - if (userData == null) { - detectableFieldId = null; - detectableRemoteId = null; + + final ArrayList<AutofillId> detectedFieldIds; + final ArrayList<Match> detectedMatches; + + if (userData != null) { + final int maxFieldsSize = UserData.getMaxFieldClassificationIdsSize(); + detectedFieldIds = new ArrayList<>(maxFieldsSize); + detectedMatches = new ArrayList<>(maxFieldsSize); } else { - // TODO(b/67867469): hardcoded to just first entry on initial refactoring. - detectableFieldId = fieldClassificationIds[0]; - detectableRemoteId = userData.getRemoteIds()[0]; + detectedFieldIds = null; + detectedMatches = null; } - int detectedFieldScore = -1; - for (int i = 0; i < mViewStates.size(); i++) { final ViewState viewState = mViewStates.valueAt(i); final int state = viewState.getState(); @@ -998,8 +999,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final AutofillValue currentValue = viewState.getCurrentValue(); if (currentValue == null) { if (sDebug) { - Slog.d(TAG, "logContextCommitted(): skipping view witout current value " - + "( " + viewState + ")"); + Slog.d(TAG, "logContextCommitted(): skipping view without current " + + "value ( " + viewState + ")"); } continue; } @@ -1060,19 +1061,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } // for j } - // Check if detectable field changed. - if (detectableFieldId != null && detectableFieldId.equals(viewState.id) - && currentValue.isText() && currentValue.getTextValue() != null) { - final String actualValue = currentValue.getTextValue().toString(); - // TODO(b/67867469): hardcoded to just first entry on initial refactoring. - final String expectedValue = userData.getValues()[0]; - if (actualValue.equalsIgnoreCase(expectedValue)) { - detectedRemoteId = detectableRemoteId; - detectedFieldScore = 0; - } else if (sVerbose) { - Slog.v(TAG, "Detection mismatch for field " + detectableFieldId); - } - // TODO(b/67867469): set score on partial hits + // Sets field classification score for field + if (userData!= null) { + setScore(detectedFieldIds, detectedMatches, userData, viewState.id, + currentValue); } } // else } // else @@ -1085,8 +1077,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + ", changedAutofillIds=" + changedFieldIds + ", changedDatasetIds=" + changedDatasetIds + ", manuallyFilledIds=" + manuallyFilledIds - + ", detectableFieldId=" + detectableFieldId - + ", detectedFieldScore=" + detectedFieldScore + + ", detectedFieldIds=" + detectedFieldIds + + ", detectedMatches=" + detectedMatches ); } @@ -1109,7 +1101,46 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds, - detectedRemoteId, detectedFieldScore); + detectedFieldIds, detectedMatches); + } + + /** + * Adds the top score match to {@code detectedFieldsIds} and {@code detectedMatches} for + * {@code fieldId} based on its {@code currentValue} and {@code userData}. + */ + private static void setScore(@NonNull ArrayList<AutofillId> detectedFieldIds, + @NonNull ArrayList<Match> detectedMatches, @NonNull UserData userData, + @NonNull AutofillId fieldId, @NonNull AutofillValue currentValue) { + + final String[] userValues = userData.getValues(); + final String[] remoteIds = userData.getRemoteIds(); + + // Sanity check + if (userValues == null || remoteIds == null || userValues.length != remoteIds.length) { + final int valuesLength = userValues == null ? -1 : userValues.length; + final int idsLength = remoteIds == null ? -1 : remoteIds.length; + Slog.w(TAG, "setScores(): user data mismatch: values.length = " + + valuesLength + ", ids.length = " + idsLength); + return; + } + String remoteId = null; + float topScore = 0; + for (int i = 0; i < userValues.length; i++) { + final String value = userValues[i]; + final float score = userData.getScorer().getScore(currentValue, value); + if (score > topScore) { + topScore = score; + remoteId = remoteIds[i]; + } + } + + if (remoteId != null && topScore > 0) { + if (sVerbose) Slog.v(TAG, "setScores(): top score for #" + fieldId + " is " + topScore); + detectedFieldIds.add(fieldId); + detectedMatches.add(new Match(remoteId, topScore)); + } else if (sVerbose) { + Slog.v(TAG, "setScores(): no top score for #" + fieldId + ": " + topScore); + } } /** diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java index 3eaee9a40b99..bd0d853ce698 100644 --- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java @@ -2389,19 +2389,24 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process"); mBackupHandler.removeMessages(MSG_RETRY_CLEAR); synchronized (mQueueLock) { - final IBackupTransport transport = - mTransportManager.getTransportBinder(transportName); - if (transport == null) { - // transport is currently unavailable -- make sure to retry + TransportClient transportClient = + mTransportManager + .getTransportClient(transportName, "BMS.clearBackupData()"); + if (transportClient == null) { + // transport is currently unregistered -- make sure to retry Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR, new ClearRetryParams(transportName, packageName)); mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL); return; } long oldId = Binder.clearCallingIdentity(); + OnTaskFinishedListener listener = + caller -> + mTransportManager.disposeOfTransportClient(transportClient, caller); mWakelock.acquire(); - Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR, - new ClearParams(transport, info)); + Message msg = mBackupHandler.obtainMessage( + MSG_RUN_CLEAR, + new ClearParams(transportClient, info, listener)); mBackupHandler.sendMessage(msg); Binder.restoreCallingIdentity(oldId); } diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index 9011b95cf614..477724de2c4d 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -268,8 +268,13 @@ public class BackupHandler extends Handler { case MSG_RUN_CLEAR: { ClearParams params = (ClearParams) msg.obj; - (new PerformClearTask(backupManagerService, params.transport, - params.packageInfo)).run(); + Runnable task = + new PerformClearTask( + backupManagerService, + params.transportClient, + params.packageInfo, + params.listener); + task.run(); break; } diff --git a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java index 7af01eac9683..84ca59b583e0 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java @@ -23,46 +23,54 @@ import android.util.Slog; import com.android.internal.backup.IBackupTransport; import com.android.server.backup.RefactoredBackupManagerService; +import com.android.server.backup.transport.TransportClient; import java.io.File; public class PerformClearTask implements Runnable { - - private RefactoredBackupManagerService backupManagerService; - IBackupTransport mTransport; - PackageInfo mPackage; + private final RefactoredBackupManagerService mBackupManagerService; + private final TransportClient mTransportClient; + private final PackageInfo mPackage; + private final OnTaskFinishedListener mListener; PerformClearTask(RefactoredBackupManagerService backupManagerService, - IBackupTransport transport, PackageInfo packageInfo) { - this.backupManagerService = backupManagerService; - mTransport = transport; + TransportClient transportClient, PackageInfo packageInfo, + OnTaskFinishedListener listener) { + mBackupManagerService = backupManagerService; + mTransportClient = transportClient; mPackage = packageInfo; + mListener = listener; } public void run() { + String callerLogString = "PerformClearTask.run()"; + IBackupTransport transport = null; try { // Clear the on-device backup state to ensure a full backup next time - File stateDir = new File(backupManagerService.getBaseStateDir(), - mTransport.transportDirName()); + File stateDir = new File(mBackupManagerService.getBaseStateDir(), + mTransportClient.getTransportDirName()); File stateFile = new File(stateDir, mPackage.packageName); stateFile.delete(); + transport = mTransportClient.connectOrThrow(callerLogString); // Tell the transport to remove all the persistent storage for the app // TODO - need to handle failures - mTransport.clearBackupData(mPackage); + transport.clearBackupData(mPackage); } catch (Exception e) { Slog.e(TAG, "Transport threw clearing data for " + mPackage + ": " + e.getMessage()); } finally { - try { - // TODO - need to handle failures - mTransport.finishBackup(); - } catch (Exception e) { - // Nothing we can do here, alas - Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage()); + if (transport != null) { + try { + // TODO - need to handle failures + transport.finishBackup(); + } catch (Exception e) { + // Nothing we can do here, alas + Slog.e(TAG, "Unable to mark clear operation finished: " + e.getMessage()); + } } - + mListener.onFinished(callerLogString); // Last but not least, release the cpu - backupManagerService.getWakelock().release(); + mBackupManagerService.getWakelock().release(); } } } diff --git a/services/backup/java/com/android/server/backup/params/ClearParams.java b/services/backup/java/com/android/server/backup/params/ClearParams.java index d744efce521a..dc3bba007443 100644 --- a/services/backup/java/com/android/server/backup/params/ClearParams.java +++ b/services/backup/java/com/android/server/backup/params/ClearParams.java @@ -18,15 +18,20 @@ package com.android.server.backup.params; import android.content.pm.PackageInfo; -import com.android.internal.backup.IBackupTransport; +import com.android.server.backup.internal.OnTaskFinishedListener; +import com.android.server.backup.transport.TransportClient; public class ClearParams { - - public IBackupTransport transport; + public TransportClient transportClient; public PackageInfo packageInfo; + public OnTaskFinishedListener listener; - public ClearParams(IBackupTransport _transport, PackageInfo _info) { - transport = _transport; - packageInfo = _info; + public ClearParams( + TransportClient transportClient, + PackageInfo packageInfo, + OnTaskFinishedListener listener) { + this.transportClient = transportClient; + this.packageInfo = packageInfo; + this.listener = listener; } } diff --git a/services/backup/java/com/android/server/backup/params/ClearRetryParams.java b/services/backup/java/com/android/server/backup/params/ClearRetryParams.java index fcf66e40162e..41b564106b55 100644 --- a/services/backup/java/com/android/server/backup/params/ClearRetryParams.java +++ b/services/backup/java/com/android/server/backup/params/ClearRetryParams.java @@ -17,12 +17,11 @@ package com.android.server.backup.params; public class ClearRetryParams { - public String transportName; public String packageName; - public ClearRetryParams(String transport, String pkg) { - transportName = transport; - packageName = pkg; + public ClearRetryParams(String transportName, String packageName) { + this.transportName = transportName; + this.packageName = packageName; } } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 04279a31d2be..763a4e494593 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -67,6 +67,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; import java.util.LinkedList; +import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -79,15 +80,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; - private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid"; - private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; - private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; + private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; + private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address"; + private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name"; private static final int ACTIVE_LOG_MAX_SIZE = 20; private static final int CRASH_LOG_MAX_SIZE = 100; private static final String REASON_AIRPLANE_MODE = "airplane mode"; private static final String REASON_DISALLOWED = "disallowed by system"; - private static final String REASON_SHARING_DISALLOWED = "sharing disallowed by system"; private static final String REASON_RESTARTED = "automatic restart"; private static final String REASON_START_CRASH = "turn-on crash"; private static final String REASON_SYSTEM_BOOT = "system boot"; @@ -130,14 +130,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MAX_ERROR_RESTART_RETRIES = 6; // Bluetooth persisted setting is off - private static final int BLUETOOTH_OFF=0; + private static final int BLUETOOTH_OFF = 0; // Bluetooth persisted setting is on // and Airplane mode won't affect Bluetooth state at start up - private static final int BLUETOOTH_ON_BLUETOOTH=1; + private static final int BLUETOOTH_ON_BLUETOOTH = 1; // Bluetooth persisted setting is on // but Airplane mode will affect Bluetooth state at start up // and Airplane mode will have higher priority. - private static final int BLUETOOTH_ON_AIRPLANE=2; + private static final int BLUETOOTH_ON_AIRPLANE = 2; private static final int SERVICE_IBLUETOOTH = 1; private static final int SERVICE_IBLUETOOTHGATT = 2; @@ -154,8 +154,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private IBinder mBluetoothBinder; private IBluetooth mBluetooth; private IBluetoothGatt mBluetoothGatt; - private final ReentrantReadWriteLock mBluetoothLock = - new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock(); private boolean mBinding; private boolean mUnbinding; @@ -175,7 +174,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mEnable; private long mTimestamp; - public ActiveLog(String packageName, boolean enable, long timestamp) { + ActiveLog(String packageName, boolean enable, long timestamp) { mPackageName = packageName; mEnable = enable; mTimestamp = timestamp; @@ -186,8 +185,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public String toString() { - return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by " - + mPackageName; + return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by " + + mPackageName; } } @@ -203,7 +202,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mEnableExternal; // Map of apps registered to keep BLE scanning on. - private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); + private Map<IBinder, ClientDeathRecipient> mBleApps = + new ConcurrentHashMap<IBinder, ClientDeathRecipient>(); private int mState; private final BluetoothHandler mHandler; @@ -212,51 +212,52 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services - private final Map <Integer, ProfileServiceConnections> mProfileServices = - new HashMap <Integer, ProfileServiceConnections>(); + private final Map<Integer, ProfileServiceConnections> mProfileServices = + new HashMap<Integer, ProfileServiceConnections>(); private final boolean mPermissionReviewRequired; private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { @Override - public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { - Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); + public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { + Message msg = + mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState); mHandler.sendMessage(msg); } }; private final UserRestrictionsListener mUserRestrictionsListener = new UserRestrictionsListener() { - @Override - public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, - Bundle prevRestrictions) { - - if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, - UserManager.DISALLOW_BLUETOOTH_SHARING)) { - updateOppLauncherComponentState(userId, newRestrictions.getBoolean( - UserManager.DISALLOW_BLUETOOTH_SHARING)); - } - - // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user. - if (userId == UserHandle.USER_SYSTEM && - UserRestrictionsUtils.restrictionsChanged( - prevRestrictions, newRestrictions, UserManager.DISALLOW_BLUETOOTH)) { - if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean( - UserManager.DISALLOW_BLUETOOTH)) { - updateOppLauncherComponentState(userId, true); // Sharing disallowed - sendDisableMsg(REASON_DISALLOWED); - } else { - updateOppLauncherComponentState(userId, newRestrictions.getBoolean( - UserManager.DISALLOW_BLUETOOTH_SHARING)); + @Override + public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, + Bundle prevRestrictions) { + + if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, + UserManager.DISALLOW_BLUETOOTH_SHARING)) { + updateOppLauncherComponentState(userId, + newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING)); + } + + // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user. + if (userId == UserHandle.USER_SYSTEM + && UserRestrictionsUtils.restrictionsChanged(prevRestrictions, + newRestrictions, UserManager.DISALLOW_BLUETOOTH)) { + if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean( + UserManager.DISALLOW_BLUETOOTH)) { + updateOppLauncherComponentState(userId, true); // Sharing disallowed + sendDisableMsg(REASON_DISALLOWED); + } else { + updateOppLauncherComponentState(userId, newRestrictions.getBoolean( + UserManager.DISALLOW_BLUETOOTH_SHARING)); + } + } } - } - } - }; + }; private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) { @Override public void onChange(boolean unused) { - synchronized(this) { + synchronized (this) { if (isBluetoothPersistedStateOn()) { if (isAirplaneModeOn()) { persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); @@ -278,8 +279,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.readLock().unlock(); } - Slog.d(TAG, "Airplane Mode change - current state: " + - BluetoothAdapter.nameForState(st)); + Slog.d(TAG, + "Airplane Mode change - current state: " + BluetoothAdapter.nameForState( + st)); if (isAirplaneModeOn()) { // Clear registered LE apps to force shut-off @@ -295,11 +297,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mEnableExternal = false; } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call onBrEdrDown", e); + Slog.e(TAG, "Unable to call onBrEdrDown", e); } finally { mBluetoothLock.readLock().unlock(); } - } else if (st == BluetoothAdapter.STATE_ON){ + } else if (st == BluetoothAdapter.STATE_ON) { sendDisableMsg(REASON_AIRPLANE_MODE); } } else if (mEnableExternal) { @@ -315,35 +317,42 @@ class BluetoothManagerService extends IBluetoothManager.Stub { String action = intent.getAction(); if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); - if (DBG) Slog.d(TAG, "Bluetooth Adapter name changed to " + newName); + if (DBG) { + Slog.d(TAG, "Bluetooth Adapter name changed to " + newName); + } if (newName != null) { storeNameAndAddress(newName, null); } } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) { String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS); if (newAddress != null) { - if (DBG) Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress); + if (DBG) { + Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress); + } storeNameAndAddress(null, newAddress); } else { - if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found"); + if (DBG) { + Slog.e(TAG, "No Bluetooth Adapter address parameter found"); + } } } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); if (Settings.Global.BLUETOOTH_ON.equals(name)) { // The Bluetooth On state may be changed during system restore. - final String prevValue = intent.getStringExtra( - Intent.EXTRA_SETTING_PREVIOUS_VALUE); - final String newValue = intent.getStringExtra( - Intent.EXTRA_SETTING_NEW_VALUE); + final String prevValue = + intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); + final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); - if (DBG) Slog.d(TAG, "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + - prevValue + ", newValue=" + newValue); + if (DBG) { + Slog.d(TAG, + "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue + + ", newValue=" + newValue); + } if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) { Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING, - newValue.equals("0") ? - RESTORE_SETTING_TO_OFF : - RESTORE_SETTING_TO_ON, 0); + newValue.equals("0") ? RESTORE_SETTING_TO_OFF + : RESTORE_SETTING_TO_ON, 0); mHandler.sendMessage(msg); } } @@ -356,8 +365,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext = context; - mPermissionReviewRequired = context.getResources().getBoolean( - com.android.internal.R.bool.config_permissionReviewRequired); + mPermissionReviewRequired = context.getResources() + .getBoolean(com.android.internal.R.bool.config_permissionReviewRequired); mActiveLogs = new LinkedList<ActiveLog>(); mCrashTimestamps = new LinkedList<Long>(); @@ -389,23 +398,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { loadStoredNameAndAddress(); if (isBluetoothPersistedStateOn()) { - if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON."); + if (DBG) { + Slog.d(TAG, "Startup: Bluetooth persisted state is ON."); + } mEnableExternal = true; } - String airplaneModeRadios = Settings.Global.getString(mContentResolver, - Settings.Global.AIRPLANE_MODE_RADIOS); - if (airplaneModeRadios == null || - airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) { + String airplaneModeRadios = + Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS); + if (airplaneModeRadios == null || airplaneModeRadios.contains( + Settings.Global.RADIO_BLUETOOTH)) { mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), - true, mAirplaneModeObserver); + Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true, + mAirplaneModeObserver); } int systemUiUid = -1; try { - systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", - PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); + systemUiUid = mContext.getPackageManager() + .getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY, + UserHandle.USER_SYSTEM); } catch (PackageManager.NameNotFoundException e) { // Some platforms, such as wearables do not have a system ui. Slog.w(TAG, "Unable to resolve SystemUI's UID.", e); @@ -416,7 +428,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /** * Returns true if airplane mode is currently on */ - private final boolean isAirplaneModeOn() { + private boolean isAirplaneModeOn() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1; } @@ -424,31 +436,32 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /** * Returns true if the Bluetooth saved state is "on" */ - private final boolean isBluetoothPersistedStateOn() { - int state = Settings.Global.getInt(mContentResolver, - Settings.Global.BLUETOOTH_ON, -1); - if (DBG) Slog.d(TAG, "Bluetooth persisted state: " + state); + private boolean isBluetoothPersistedStateOn() { + int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1); + if (DBG) { + Slog.d(TAG, "Bluetooth persisted state: " + state); + } return state != BLUETOOTH_OFF; } /** * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH */ - private final boolean isBluetoothPersistedStateOnBluetooth() { - return Settings.Global.getInt(mContentResolver, - Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; + private boolean isBluetoothPersistedStateOnBluetooth() { + return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, + BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; } /** * Save the Bluetooth on/off state */ private void persistBluetoothSetting(int value) { - if (DBG) Slog.d(TAG, "Persisting Bluetooth Setting: " + value); + if (DBG) { + Slog.d(TAG, "Persisting Bluetooth Setting: " + value); + } // waive WRITE_SECURE_SETTINGS permission check long callingIdentity = Binder.clearCallingIdentity(); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLUETOOTH_ON, - value); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value); Binder.restoreCallingIdentity(callingIdentity); } @@ -458,7 +471,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * @return */ private boolean isNameAndAddressSet() { - return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; + return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0; } /** @@ -466,17 +479,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * in the local cache */ private void loadStoredNameAndAddress() { - if (DBG) Slog.d(TAG, "Loading stored name and address"); - if (mContext.getResources().getBoolean - (com.android.internal.R.bool.config_bluetooth_address_validation) && - Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) { + if (DBG) { + Slog.d(TAG, "Loading stored name and address"); + } + if (mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation) + && Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) + == 0) { // if the valid flag is not set, don't load the address and name - if (DBG) Slog.d(TAG, "invalid bluetooth name and address stored"); + if (DBG) { + Slog.d(TAG, "invalid bluetooth name and address stored"); + } return; } mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); - if (DBG) Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); + if (DBG) { + Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); + } } /** @@ -489,15 +509,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (name != null) { Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); mName = name; - if (DBG) Slog.d(TAG,"Stored Bluetooth name: " + - Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); + if (DBG) { + Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver, + SECURE_SETTINGS_BLUETOOTH_NAME)); + } } if (address != null) { Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); - mAddress=address; - if (DBG) Slog.d(TAG,"Stored Bluetoothaddress: " + - Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); + mAddress = address; + if (DBG) { + Slog.d(TAG, + "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver, + SECURE_SETTINGS_BLUETOOTH_ADDRESS)); + } } if ((name != null) && (address != null)) { @@ -505,7 +530,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } - public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ + public IBluetooth registerAdapter(IBluetoothManagerCallback callback) { if (callback == null) { Slog.w(TAG, "Callback is null in registerAdapter"); return null; @@ -522,19 +547,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Slog.w(TAG, "Callback is null in unregisterAdapter"); return; } - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); msg.obj = callback; mHandler.sendMessage(msg); } public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (callback == null) { - Slog.w(TAG, "registerStateChangeCallback: Callback is null!"); - return; + Slog.w(TAG, "registerStateChangeCallback: Callback is null!"); + return; } Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); msg.obj = callback; @@ -542,11 +565,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (callback == null) { - Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!"); - return; + Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!"); + return; } Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); msg.obj = callback; @@ -554,15 +576,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public boolean isEnabled() { - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG,"isEnabled(): not allowed for non-active and non system user"); + if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { + Slog.w(TAG, "isEnabled(): not allowed for non-active and non system user"); return false; } try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) return mBluetooth.isEnabled(); + if (mBluetooth != null) { + return mBluetooth.isEnabled(); + } } catch (RemoteException e) { Slog.e(TAG, "isEnabled()", e); } finally { @@ -572,15 +595,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public int getState() { - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { + if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { Slog.w(TAG, "getState(): report OFF for non-active and non system user"); return BluetoothAdapter.STATE_OFF; } try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) return mBluetooth.getState(); + if (mBluetooth != null) { + return mBluetooth.getState(); + } } catch (RemoteException e) { Slog.e(TAG, "getState()", e); } finally { @@ -592,26 +616,29 @@ class BluetoothManagerService extends IBluetoothManager.Stub { class ClientDeathRecipient implements IBinder.DeathRecipient { private String mPackageName; - public ClientDeathRecipient(String packageName) { + ClientDeathRecipient(String packageName) { mPackageName = packageName; } public void binderDied() { - if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName); + if (DBG) { + Slog.d(TAG, "Binder is dead - unregister " + mPackageName); + } if (isBleAppPresent()) { - // Nothing to do, another app is here. - return; + // Nothing to do, another app is here. + return; + } + if (DBG) { + Slog.d(TAG, "Disabling LE only mode after application crash"); } - if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash"); try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null && - mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) { + if (mBluetooth != null && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) { mEnable = false; mBluetooth.onBrEdrDown(); } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call onBrEdrDown", e); + Slog.e(TAG, "Unable to call onBrEdrDown", e); } finally { mBluetoothLock.readLock().unlock(); } @@ -641,15 +668,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void onChange(boolean selfChange) { if (isBleScanAlwaysAvailable()) { - // Nothing to do - return; + // Nothing to do + return; } // BLE scan is not available. disableBleScanMode(); clearBleApps(); try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) mBluetooth.onBrEdrDown(); + if (mBluetooth != null) { + mBluetooth.onBrEdrDown(); + } } catch (RemoteException e) { Slog.e(TAG, "error when disabling bluetooth", e); } finally { @@ -659,8 +688,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { }; mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), - false, contentObserver); + Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false, + contentObserver); } // Disable ble scan only mode. @@ -668,7 +697,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.writeLock().lock(); if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) { - if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable"); + if (DBG) { + Slog.d(TAG, "Reseting the mEnable flag for clean disable"); + } mEnable = false; } } catch (RemoteException e) { @@ -688,15 +719,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub { throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!"); } mBleApps.put(token, deathRec); - if (DBG) Slog.d(TAG, "Registered for death of " + packageName); + if (DBG) { + Slog.d(TAG, "Registered for death of " + packageName); + } } else if (!enable && r != null) { // Unregister death recipient as the app goes away. token.unlinkToDeath(r, 0); mBleApps.remove(token); - if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName); + if (DBG) { + Slog.d(TAG, "Unregistered for death of " + packageName); + } } int appCount = mBleApps.size(); - if (DBG) Slog.d(TAG, appCount + " registered Ble Apps"); + if (DBG) { + Slog.d(TAG, appCount + " registered Ble Apps"); + } if (appCount == 0 && mEnable) { disableBleScanMode(); } @@ -713,7 +750,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /** @hide */ public boolean isBleAppPresent() { - if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size()); + if (DBG) { + Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size()); + } return mBleApps.size() > 0; } @@ -721,17 +760,23 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Action taken when GattService is turned on */ private void onBluetoothGattServiceUp() { - if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up"); + if (DBG) { + Slog.d(TAG, "BluetoothGatt Service is Up"); + } try { mBluetoothLock.readLock().lock(); if (mBluetooth == null) { - if (DBG) Slog.w(TAG, "onBluetoothServiceUp: mBluetooth is null!"); + if (DBG) { + Slog.w(TAG, "onBluetoothServiceUp: mBluetooth is null!"); + } return; } int st = mBluetooth.getState(); if (st != BluetoothAdapter.STATE_BLE_ON) { - if (DBG) Slog.v(TAG, "onBluetoothServiceUp: state isn't BLE_ON: " + - BluetoothAdapter.nameForState(st)); + if (DBG) { + Slog.v(TAG, "onBluetoothServiceUp: state isn't BLE_ON: " + + BluetoothAdapter.nameForState(st)); + } return; } if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) { @@ -740,7 +785,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call onServiceUp", e); + Slog.e(TAG, "Unable to call onServiceUp", e); } finally { mBluetoothLock.readLock().unlock(); } @@ -751,7 +796,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * and turn off all service and stack if no LE app needs it */ private void sendBrEdrDownCallback() { - if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks"); + if (DBG) { + Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks"); + } if (mBluetooth == null) { Slog.w(TAG, "Bluetooth handle is null"); @@ -768,7 +815,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else { try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) mBluetooth.onBrEdrDown(); + if (mBluetooth != null) { + mBluetooth.onBrEdrDown(); + } } catch (RemoteException e) { Slog.e(TAG, "Call to onBrEdrDown() failed.", e); } finally { @@ -778,8 +827,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } - public boolean enableNoAutoConnect(String packageName) - { + public boolean enableNoAutoConnect(String packageName) { if (isBluetoothDisallowed()) { if (DBG) { Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed"); @@ -788,11 +836,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permission"); + "Need BLUETOOTH ADMIN permission"); if (DBG) { - Slog.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + - " mBinding = " + mBinding); + Slog.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = " + + mBinding); } int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); @@ -800,7 +848,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { throw new SecurityException("no permission to enable Bluetooth quietly"); } - synchronized(mReceiver) { + synchronized (mReceiver) { mQuietEnableExternal = true; mEnableExternal = true; sendEnableMsg(true, packageName); @@ -814,7 +862,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (isBluetoothDisallowed()) { if (DBG) { - Slog.d(TAG,"enable(): not enabling - bluetooth disallowed"); + Slog.d(TAG, "enable(): not enabling - bluetooth disallowed"); } return false; } @@ -828,26 +876,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); - if (!isEnabled() && mPermissionReviewRequired - && startConsentUiIfNeeded(packageName, callingUid, - BluetoothAdapter.ACTION_REQUEST_ENABLE)) { + if (!isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, + callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { return false; } } if (DBG) { - Slog.d(TAG,"enable(" + packageName + "): mBluetooth =" + mBluetooth + - " mBinding = " + mBinding + " mState = " + - BluetoothAdapter.nameForState(mState)); + Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = " + + mBinding + " mState = " + BluetoothAdapter.nameForState(mState)); } - synchronized(mReceiver) { + synchronized (mReceiver) { mQuietEnableExternal = false; mEnableExternal = true; // waive WRITE_SECURE_SETTINGS permission check sendEnableMsg(false, packageName); } - if (DBG) Slog.d(TAG, "enable returning"); + if (DBG) { + Slog.d(TAG, "enable returning"); + } return true; } @@ -864,19 +912,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); - if (isEnabled() && mPermissionReviewRequired - && startConsentUiIfNeeded(packageName, callingUid, - BluetoothAdapter.ACTION_REQUEST_DISABLE)) { + if (isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, + callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { return false; } } if (DBG) { - Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth + - " mBinding = " + mBinding); + Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); } - synchronized(mReceiver) { + synchronized (mReceiver) { if (persist) { persistBluetoothSetting(BLUETOOTH_OFF); } @@ -886,8 +932,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - private boolean startConsentUiIfNeeded(String packageName, - int callingUid, String intentAction) throws RemoteException { + private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction) + throws RemoteException { try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() @@ -895,14 +941,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub { PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); if (applicationInfo.uid != callingUid) { - throw new SecurityException("Package " + callingUid - + " not in uid " + callingUid); + throw new SecurityException("Package " + callingUid + " not in uid " + callingUid); } Intent intent = new Intent(intentAction); intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); try { mContext.startActivity(intent); } catch (ActivityNotFoundException e) { @@ -918,13 +963,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void unbindAndFinish() { if (DBG) { - Slog.d(TAG,"unbindAndFinish(): " + mBluetooth + - " mBinding = " + mBinding + " mUnbinding = " + mUnbinding); + Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding + + " mUnbinding = " + mUnbinding); } try { mBluetoothLock.writeLock().lock(); - if (mUnbinding) return; + if (mUnbinding) { + return; + } mUnbinding = true; mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE); @@ -933,7 +980,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetooth.unregisterCallback(mBluetoothCallback); } catch (RemoteException re) { - Slog.e(TAG, "Unable to unregister BluetoothCallback",re); + Slog.e(TAG, "Unable to unregister BluetoothCallback", re); } mBluetoothBinder = null; mBluetooth = null; @@ -959,8 +1006,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { IBluetoothProfileServiceConnection proxy) { if (!mEnable) { if (DBG) { - Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile + - ", while Bluetooth was disabled"); + Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile + + ", while Bluetooth was disabled"); } return false; } @@ -968,15 +1015,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { if (DBG) { - Slog.d(TAG, "Creating new ProfileServiceConnections object for" - + " profile: " + bluetoothProfile); + Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + + bluetoothProfile); } - if (bluetoothProfile != BluetoothProfile.HEADSET) return false; + if (bluetoothProfile != BluetoothProfile.HEADSET) { + return false; + } Intent intent = new Intent(IBluetoothHeadset.class.getName()); psc = new ProfileServiceConnections(intent); - if (!psc.bindService()) return false; + if (!psc.bindService()) { + return false; + } mProfileServices.put(new Integer(bluetoothProfile), psc); } @@ -1022,7 +1073,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * PHASE_SYSTEM_SERVICES_READY. */ public void handleOnBootPhase() { - if (DBG) Slog.d(TAG, "Bluetooth boot completed"); + if (DBG) { + Slog.d(TAG, "Bluetooth boot completed"); + } UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); @@ -1031,10 +1084,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return; } if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { - if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth."); + if (DBG) { + Slog.d(TAG, "Auto-enabling Bluetooth."); + } sendEnableMsg(mQuietEnableExternal, REASON_SYSTEM_BOOT); } else if (!isNameAndAddressSet()) { - if (DBG) Slog.d(TAG, "Getting adapter name and address"); + if (DBG) { + Slog.d(TAG, "Getting adapter name and address"); + } Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); } @@ -1044,7 +1101,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Called when switching to a different foreground user. */ public void handleOnSwitchUser(int userHandle) { - if (DBG) Slog.d(TAG, "User " + userHandle + " switched"); + if (DBG) { + Slog.d(TAG, "User " + userHandle + " switched"); + } mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget(); } @@ -1052,7 +1111,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Called when user is unlocked. */ public void handleOnUnlockUser(int userHandle) { - if (DBG) Slog.d(TAG, "User " + userHandle + " unlocked"); + if (DBG) { + Slog.d(TAG, "User " + userHandle + " unlocked"); + } mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget(); } @@ -1060,10 +1121,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * This class manages the clients connected to a given ProfileService * and maintains the connection with that service. */ - final private class ProfileServiceConnections implements ServiceConnection, - IBinder.DeathRecipient { + private final class ProfileServiceConnections + implements ServiceConnection, IBinder.DeathRecipient { final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = - new RemoteCallbackList <IBluetoothProfileServiceConnection>(); + new RemoteCallbackList<IBluetoothProfileServiceConnection>(); IBinder mService; ComponentName mClassName; Intent mIntent; @@ -1076,8 +1137,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private boolean bindService() { - if (mIntent != null && mService == null && - doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { + if (mIntent != null && mService == null && doBind(mIntent, this, 0, + UserHandle.CURRENT_OR_SELF)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); @@ -1090,7 +1151,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private void addProxy(IBluetoothProfileServiceConnection proxy) { mProxies.register(proxy); if (mService != null) { - try{ + try { proxy.onServiceConnected(mClassName, mService); } catch (RemoteException e) { Slog.e(TAG, "Unable to connect to proxy", e); @@ -1158,7 +1219,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void onServiceDisconnected(ComponentName className) { - if (mService == null) return; + if (mService == null) { + return; + } mService.unlinkToDeath(this, 0); mService = null; mClassName = null; @@ -1187,8 +1250,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void binderDied() { if (DBG) { - Slog.w(TAG, "Profile service for profile: " + mClassName - + " died."); + Slog.w(TAG, "Profile service for profile: " + mClassName + " died."); } onServiceDisconnected(mClassName); // Trigger rebind @@ -1201,12 +1263,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private void sendBluetoothStateCallback(boolean isUp) { try { int n = mStateChangeCallbacks.beginBroadcast(); - if (DBG) Slog.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); - for (int i=0; i <n;i++) { + if (DBG) { + Slog.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n + + " receivers."); + } + for (int i = 0; i < n; i++) { try { mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); + Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e); } } } finally { @@ -1220,11 +1285,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private void sendBluetoothServiceUpCallback() { try { int n = mCallbacks.beginBroadcast(); - Slog.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); - for (int i=0; i <n;i++) { + Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers."); + for (int i = 0; i < n; i++) { try { mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); - } catch (RemoteException e) { + } catch (RemoteException e) { Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); } } @@ -1232,17 +1297,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mCallbacks.finishBroadcast(); } } + /** * Inform BluetoothAdapter instances that Adapter service is down */ private void sendBluetoothServiceDownCallback() { try { int n = mCallbacks.beginBroadcast(); - Slog.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); - for (int i=0; i <n;i++) { + Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers."); + for (int i = 0; i < n; i++) { try { mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); - } catch (RemoteException e) { + } catch (RemoteException e) { Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); } } @@ -1252,12 +1318,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public String getAddress() { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG,"getAddress(): not allowed for non-active and non system user"); + if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { + Slog.w(TAG, "getAddress(): not allowed for non-active and non system user"); return null; } @@ -1268,9 +1332,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) return mBluetooth.getAddress(); + if (mBluetooth != null) { + return mBluetooth.getAddress(); + } } catch (RemoteException e) { - Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e); + Slog.e(TAG, + "getAddress(): Unable to retrieve address remotely. Returning cached address", + e); } finally { mBluetoothLock.readLock().unlock(); } @@ -1282,18 +1350,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public String getName() { - mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { - Slog.w(TAG,"getName(): not allowed for non-active and non system user"); + if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { + Slog.w(TAG, "getName(): not allowed for non-active and non system user"); return null; } try { mBluetoothLock.readLock().lock(); - if (mBluetooth != null) return mBluetooth.getName(); + if (mBluetooth != null) { + return mBluetooth.getName(); + } } catch (RemoteException e) { Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e); } finally { @@ -1309,7 +1377,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private class BluetoothServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName componentName, IBinder service) { String name = componentName.getClassName(); - if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + name); + if (DBG) { + Slog.d(TAG, "BluetoothServiceConnection: " + name); + } Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); if (name.equals("com.android.bluetooth.btservice.AdapterService")) { msg.arg1 = SERVICE_IBLUETOOTH; @@ -1326,7 +1396,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void onServiceDisconnected(ComponentName componentName) { // Called if we unexpectedly disconnect. String name = componentName.getClassName(); - if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name); + if (DBG) { + Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name); + } Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); if (name.equals("com.android.bluetooth.btservice.AdapterService")) { msg.arg1 = SERVICE_IBLUETOOTH; @@ -1345,7 +1417,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private class BluetoothHandler extends Handler { boolean mGetNameAddressOnly = false; - public BluetoothHandler(Looper looper) { + BluetoothHandler(Looper looper) { super(looper); } @@ -1353,26 +1425,29 @@ class BluetoothManagerService extends IBluetoothManager.Stub { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_GET_NAME_AND_ADDRESS: - if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); + if (DBG) { + Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); + } try { mBluetoothLock.writeLock().lock(); if ((mBluetooth == null) && (!mBinding)) { - if (DBG) Slog.d(TAG, "Binding to service to get name and address"); + if (DBG) { + Slog.d(TAG, "Binding to service to get name and address"); + } mGetNameAddressOnly = true; Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); Intent i = new Intent(IBluetooth.class.getName()); if (!doBind(i, mConnection, - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, - UserHandle.CURRENT)) { + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, + UserHandle.CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); } else { mBinding = true; } } else if (mBluetooth != null) { try { - storeNameAndAddress(mBluetooth.getName(), - mBluetooth.getAddress()); + storeNameAndAddress(mBluetooth.getName(), mBluetooth.getAddress()); } catch (RemoteException re) { Slog.e(TAG, "Unable to grab names", re); } @@ -1431,15 +1506,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // on the order of (2 * SERVICE_RESTART_TIME_MS). // waitForOnOff(false, true); - Message restartMsg = mHandler.obtainMessage( - MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, - 2 * SERVICE_RESTART_TIME_MS); + Message restartMsg = + mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); + mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS); } break; case MESSAGE_DISABLE: - if (DBG) Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth); + if (DBG) { + Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth); + } mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); if (mEnable && mBluetooth != null) { waitForOnOff(true, false); @@ -1455,45 +1531,45 @@ class BluetoothManagerService extends IBluetoothManager.Stub { case MESSAGE_RESTORE_USER_SETTING: try { if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) { - if (DBG) Slog.d(TAG, "Restore Bluetooth state to disabled"); + if (DBG) { + Slog.d(TAG, "Restore Bluetooth state to disabled"); + } disable(REASON_RESTORE_USER_SETTING, true); } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) { - if (DBG) Slog.d(TAG, "Restore Bluetooth state to enabled"); + if (DBG) { + Slog.d(TAG, "Restore Bluetooth state to enabled"); + } enable(REASON_RESTORE_USER_SETTING); } } catch (RemoteException e) { - Slog.e(TAG,"Unable to change Bluetooth On setting", e); + Slog.e(TAG, "Unable to change Bluetooth On setting", e); } break; - case MESSAGE_REGISTER_ADAPTER: - { + case MESSAGE_REGISTER_ADAPTER: { IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; mCallbacks.register(callback); break; } - case MESSAGE_UNREGISTER_ADAPTER: - { + case MESSAGE_UNREGISTER_ADAPTER: { IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; mCallbacks.unregister(callback); break; } - case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: - { - IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; + case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: { + IBluetoothStateChangeCallback callback = + (IBluetoothStateChangeCallback) msg.obj; mStateChangeCallbacks.register(callback); break; } - case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: - { - IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; + case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: { + IBluetoothStateChangeCallback callback = + (IBluetoothStateChangeCallback) msg.obj; mStateChangeCallbacks.unregister(callback); break; } - case MESSAGE_ADD_PROXY_DELAYED: - { - ProfileServiceConnections psc = mProfileServices.get( - new Integer(msg.arg1)); + case MESSAGE_ADD_PROXY_DELAYED: { + ProfileServiceConnections psc = mProfileServices.get(new Integer(msg.arg1)); if (psc == null) { break; } @@ -1502,8 +1578,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { psc.addProxy(proxy); break; } - case MESSAGE_BIND_PROFILE_SERVICE: - { + case MESSAGE_BIND_PROFILE_SERVICE: { ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { @@ -1512,16 +1587,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { psc.bindService(); break; } - case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: - { - if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); + case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { + if (DBG) { + Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); + } IBinder service = (IBinder) msg.obj; try { mBluetoothLock.writeLock().lock(); if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { - mBluetoothGatt = IBluetoothGatt.Stub - .asInterface(Binder.allowBlocking(service)); + mBluetoothGatt = + IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service)); onBluetoothGattServiceUp(); break; } // else must be SERVICE_IBLUETOOTH @@ -1536,31 +1612,33 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (!isNameAndAddressSet()) { Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); - if (mGetNameAddressOnly) return; + if (mGetNameAddressOnly) { + return; + } } //Register callback object try { mBluetooth.registerCallback(mBluetoothCallback); } catch (RemoteException re) { - Slog.e(TAG, "Unable to register BluetoothCallback",re); + Slog.e(TAG, "Unable to register BluetoothCallback", re); } //Inform BluetoothAdapter instances that service is up sendBluetoothServiceUpCallback(); //Do enable request try { - if (mQuietEnable == false) { + if (mQuietEnable) { if (!mBluetooth.enable()) { - Slog.e(TAG,"IBluetooth.enable() returned false"); + Slog.e(TAG, "IBluetooth.enable() returned false"); } } else { if (!mBluetooth.enableNoAutoConnect()) { - Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); + Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false"); } } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call enable()",e); + Slog.e(TAG, "Unable to call enable()", e); } } finally { mBluetoothLock.writeLock().unlock(); @@ -1573,43 +1651,42 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } - case MESSAGE_BLUETOOTH_STATE_CHANGE: - { + case MESSAGE_BLUETOOTH_STATE_CHANGE: { int prevState = msg.arg1; int newState = msg.arg2; if (DBG) { - Slog.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(prevState) + " > " + - BluetoothAdapter.nameForState(newState)); + Slog.d(TAG, + "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState( + prevState) + " > " + BluetoothAdapter.nameForState( + newState)); } mState = newState; bluetoothStateChangeHandler(prevState, newState); // handle error state transition case from TURNING_ON to OFF // unbind and rebind bluetooth service and enable bluetooth - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && - (newState == BluetoothAdapter.STATE_OFF) && - (mBluetooth != null) && mEnable) { + if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState + == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) { recoverBluetoothServiceFromError(false); } - if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && - (newState == BluetoothAdapter.STATE_BLE_ON) && - (mBluetooth != null) && mEnable) { + if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState + == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) { recoverBluetoothServiceFromError(true); } // If we tried to enable BT while BT was in the process of shutting down, // wait for the BT process to fully tear down and then force a restart // here. This is a bit of a hack (b/29363429). - if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && - (newState == BluetoothAdapter.STATE_OFF)) { + if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState + == BluetoothAdapter.STATE_OFF)) { if (mEnable) { Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); waitForOnOff(false, true); - Message restartMsg = mHandler.obtainMessage( - MESSAGE_RESTART_BLUETOOTH_SERVICE); + Message restartMsg = + mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS); } } - if (newState == BluetoothAdapter.STATE_ON || - newState == BluetoothAdapter.STATE_BLE_ON) { + if (newState == BluetoothAdapter.STATE_ON + || newState == BluetoothAdapter.STATE_BLE_ON) { // bluetooth is working, reset the counter if (mErrorRecoveryRetryCounter != 0) { Slog.w(TAG, "bluetooth is recovered from error"); @@ -1618,14 +1695,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } - case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: - { + case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: { Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")"); try { mBluetoothLock.writeLock().lock(); if (msg.arg1 == SERVICE_IBLUETOOTH) { // if service is unbinded already, do nothing and return - if (mBluetooth == null) break; + if (mBluetooth == null) { + break; + } mBluetooth = null; } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { mBluetoothGatt = null; @@ -1644,33 +1722,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (mEnable) { mEnable = false; // Send a Bluetooth Restart message - Message restartMsg = mHandler.obtainMessage( - MESSAGE_RESTART_BLUETOOTH_SERVICE); - mHandler.sendMessageDelayed(restartMsg, - SERVICE_RESTART_TIME_MS); + Message restartMsg = + mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); + mHandler.sendMessageDelayed(restartMsg, SERVICE_RESTART_TIME_MS); } sendBluetoothServiceDownCallback(); // Send BT state broadcast to update // the BT icon correctly - if ((mState == BluetoothAdapter.STATE_TURNING_ON) || - (mState == BluetoothAdapter.STATE_ON)) { + if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState + == BluetoothAdapter.STATE_ON)) { bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); + BluetoothAdapter.STATE_TURNING_OFF); mState = BluetoothAdapter.STATE_TURNING_OFF; } if (mState == BluetoothAdapter.STATE_TURNING_OFF) { bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); + BluetoothAdapter.STATE_OFF); } mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); mState = BluetoothAdapter.STATE_OFF; break; } - case MESSAGE_RESTART_BLUETOOTH_SERVICE: - { + case MESSAGE_RESTART_BLUETOOTH_SERVICE: { Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE"); /* Enable without persisting the setting as it doesnt change when IBluetooth @@ -1687,8 +1763,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.writeLock().unlock(); break; } - case MESSAGE_TIMEOUT_UNBIND: - { + case MESSAGE_TIMEOUT_UNBIND: { Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); mBluetoothLock.writeLock().lock(); mUnbinding = false; @@ -1697,7 +1772,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } case MESSAGE_USER_SWITCHED: { - if (DBG) Slog.d(TAG, "MESSAGE_USER_SWITCHED"); + if (DBG) { + Slog.d(TAG, "MESSAGE_USER_SWITCHED"); + } mHandler.removeMessages(MESSAGE_USER_SWITCHED); /* disable and enable BT when detect a user switch */ @@ -1735,12 +1812,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, - BluetoothAdapter.STATE_TURNING_OFF); + BluetoothAdapter.STATE_TURNING_OFF); boolean didDisableTimeout = !waitForOnOff(false, true); bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, - BluetoothAdapter.STATE_OFF); + BluetoothAdapter.STATE_OFF); sendBluetoothServiceDownCallback(); try { @@ -1785,14 +1862,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub { break; } case MESSAGE_USER_UNLOCKED: { - if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED"); + if (DBG) { + Slog.d(TAG, "MESSAGE_USER_UNLOCKED"); + } mHandler.removeMessages(MESSAGE_USER_SWITCHED); if (mEnable && !mBinding && (mBluetooth == null)) { // We should be connected, but we gave up for some // reason; maybe the Bluetooth service wasn't encryption // aware, so try binding again. - if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock"); + if (DBG) { + Slog.d(TAG, "Enabled but not bound; retrying after unlock"); + } handleEnable(mQuietEnable); } } @@ -1807,10 +1888,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mBluetoothLock.writeLock().lock(); if ((mBluetooth == null) && (!mBinding)) { //Start bind timeout and bind - Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); - mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); + Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); + mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); Intent i = new Intent(IBluetooth.class.getName()); - if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, + if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); } else { @@ -1820,17 +1901,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { //Enable bluetooth try { if (!mQuietEnable) { - if(!mBluetooth.enable()) { - Slog.e(TAG,"IBluetooth.enable() returned false"); + if (!mBluetooth.enable()) { + Slog.e(TAG, "IBluetooth.enable() returned false"); } - } - else { - if(!mBluetooth.enableNoAutoConnect()) { - Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); + } else { + if (!mBluetooth.enableNoAutoConnect()) { + Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false"); } } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call enable()",e); + Slog.e(TAG, "Unable to call enable()", e); } } } finally { @@ -1852,13 +1932,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { - if (DBG) Slog.d(TAG,"Sending off request."); + if (DBG) { + Slog.d(TAG, "Sending off request."); + } if (!mBluetooth.disable()) { - Slog.e(TAG,"IBluetooth.disable() returned false"); + Slog.e(TAG, "IBluetooth.disable() returned false"); } } } catch (RemoteException e) { - Slog.e(TAG,"Unable to call disable()",e); + Slog.e(TAG, "Unable to call disable()", e); } finally { mBluetoothLock.readLock().unlock(); } @@ -1876,15 +1958,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { boolean valid = false; try { foregroundUser = ActivityManager.getCurrentUser(); - valid = (callingUser == foregroundUser) || - parentUser == foregroundUser || - callingAppId == Process.NFC_UID || - callingAppId == mSystemUiUid; + valid = (callingUser == foregroundUser) || parentUser == foregroundUser + || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid; if (DBG && !valid) { - Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid - + " callingUser=" + callingUser - + " parentUser=" + parentUser - + " foregroundUser=" + foregroundUser); + Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" + + callingUser + " parentUser=" + parentUser + " foregroundUser=" + + foregroundUser); } } finally { Binder.restoreCallingIdentity(callingIdentity); @@ -1893,8 +1972,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private void sendBleStateChanged(int prevState, int newState) { - if (DBG) Slog.d(TAG,"Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + - " > " + BluetoothAdapter.nameForState(newState)); + if (DBG) { + Slog.d(TAG, + "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > " + + BluetoothAdapter.nameForState(newState)); + } // Send broadcast message to everyone else Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); @@ -1909,14 +1991,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return; } // Notify all proxy objects first of adapter state change - if (newState == BluetoothAdapter.STATE_BLE_ON || - newState == BluetoothAdapter.STATE_OFF) { + if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) { boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF - && newState == BluetoothAdapter.STATE_BLE_ON); + && newState == BluetoothAdapter.STATE_BLE_ON); if (newState == BluetoothAdapter.STATE_OFF) { // If Bluetooth is off, send service down event to proxy objects, and unbind - if (DBG) Slog.d(TAG, "Bluetooth is complete send Service Down"); + if (DBG) { + Slog.d(TAG, "Bluetooth is complete send Service Down"); + } sendBluetoothServiceDownCallback(); unbindAndFinish(); sendBleStateChanged(prevState, newState); @@ -1925,16 +2008,23 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else if (!intermediate_off) { // connect to GattService - if (DBG) Slog.d(TAG, "Bluetooth is in LE only mode"); + if (DBG) { + Slog.d(TAG, "Bluetooth is in LE only mode"); + } if (mBluetoothGatt != null) { - if (DBG) Slog.d(TAG, "Calling BluetoothGattServiceUp"); + if (DBG) { + Slog.d(TAG, "Calling BluetoothGattServiceUp"); + } onBluetoothGattServiceUp(); } else { - if (DBG) Slog.d(TAG, "Binding Bluetooth GATT service"); - if (mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_BLUETOOTH_LE)) { + if (DBG) { + Slog.d(TAG, "Binding Bluetooth GATT service"); + } + if (mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Intent i = new Intent(IBluetoothGatt.class.getName()); - doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT); + doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, + UserHandle.CURRENT); } } sendBleStateChanged(prevState, newState); @@ -1942,7 +2032,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { isStandardBroadcast = false; } else if (intermediate_off) { - if (DBG) Slog.d(TAG, "Intermediate off, back to LE only mode"); + if (DBG) { + Slog.d(TAG, "Intermediate off, back to LE only mode"); + } // For LE only mode, broadcast as is sendBleStateChanged(prevState, newState); sendBluetoothStateCallback(false); // BT is OFF for general users @@ -1955,13 +2047,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub { sendBluetoothStateCallback(isUp); sendBleStateChanged(prevState, newState); - } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON || - newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) { + } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON + || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) { sendBleStateChanged(prevState, newState); isStandardBroadcast = false; - } else if (newState == BluetoothAdapter.STATE_TURNING_ON || - newState == BluetoothAdapter.STATE_TURNING_OFF) { + } else if (newState == BluetoothAdapter.STATE_TURNING_ON + || newState == BluetoothAdapter.STATE_TURNING_OFF) { sendBleStateChanged(prevState, newState); } @@ -1988,13 +2080,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub { while (i < 10) { try { mBluetoothLock.readLock().lock(); - if (mBluetooth == null) break; + if (mBluetooth == null) { + break; + } if (on) { - if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; + if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) { + return true; + } } else if (off) { - if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; + if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) { + return true; + } } else { - if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; + if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) { + return true; + } } } catch (RemoteException e) { Slog.e(TAG, "getState()", e); @@ -2009,7 +2109,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } i++; } - Slog.e(TAG,"waitForOnOff time out"); + Slog.e(TAG, "waitForOnOff time out"); return false; } @@ -2019,8 +2119,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private void sendEnableMsg(boolean quietMode, String packageName) { - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, - quietMode ? 1 : 0, 0)); + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0)); addActiveLog(packageName, true); mLastEnabledTime = SystemClock.elapsedRealtime(); } @@ -2035,15 +2134,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private void addCrashLog() { - synchronized (mCrashTimestamps) { - if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) mCrashTimestamps.removeFirst(); - mCrashTimestamps.add(System.currentTimeMillis()); - mCrashes++; - } + synchronized (mCrashTimestamps) { + if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) { + mCrashTimestamps.removeFirst(); + } + mCrashTimestamps.add(System.currentTimeMillis()); + mCrashes++; + } } private void recoverBluetoothServiceFromError(boolean clearBle) { - Slog.e(TAG,"recoverBluetoothServiceFromError"); + Slog.e(TAG, "recoverBluetoothServiceFromError"); try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { @@ -2082,15 +2183,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mState = BluetoothAdapter.STATE_OFF; if (clearBle) { - clearBleApps(); + clearBleApps(); } mEnable = false; if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { // Send a Bluetooth Restart message to reenable bluetooth - Message restartMsg = mHandler.obtainMessage( - MESSAGE_RESTART_BLUETOOTH_SERVICE); + Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); } else { // todo: notify user to power down and power up phone to make bluetooth work. @@ -2118,9 +2218,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) { final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity"); - final int newState = bluetoothSharingDisallowed - ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED - : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + final int newState = + bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED + : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; try { final IPackageManager imp = AppGlobals.getPackageManager(); imp.setComponentEnabledSetting(oppLauncherComponent, newState, @@ -2132,7 +2232,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; + if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) { + return; + } String errorMsg = null; boolean protoOut = (args.length > 0) && args[0].startsWith("--proto"); @@ -2145,11 +2247,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { writer.println(" name: " + mName); if (mEnable) { long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime; - String onDurationString = String.format("%02d:%02d:%02d.%03d", - (int)(onDuration / (1000 * 60 * 60)), - (int)((onDuration / (1000 * 60)) % 60), - (int)((onDuration / 1000) % 60), - (int)(onDuration % 1000)); + String onDurationString = String.format(Locale.US, "%02d:%02d:%02d.%03d", + (int) (onDuration / (1000 * 60 * 60)), + (int) ((onDuration / (1000 * 60)) % 60), (int) ((onDuration / 1000) % 60), + (int) (onDuration % 1000)); writer.println(" time since enabled: " + onDurationString); } @@ -2162,14 +2263,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } - writer.println("\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s")); - if (mCrashes == CRASH_LOG_MAX_SIZE) writer.println("(last " + CRASH_LOG_MAX_SIZE + ")"); + writer.println( + "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s")); + if (mCrashes == CRASH_LOG_MAX_SIZE) { + writer.println("(last " + CRASH_LOG_MAX_SIZE + ")"); + } for (Long time : mCrashTimestamps) { - writer.println(" " + timeToLog(time.longValue())); + writer.println(" " + timeToLog(time)); } - writer.println("\n" + mBleApps.size() + " BLE app" + - (mBleApps.size() == 1 ? "" : "s") + "registered"); + writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s") + + "registered"); for (ClientDeathRecipient app : mBleApps.values()) { writer.println(" " + app.getPackageName()); } @@ -2194,7 +2298,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (errorMsg != null) { // Silently return if we are extracting metrics in Protobuf format - if (protoOut) return; + if (protoOut) { + return; + } writer.println(errorMsg); } } diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java index cad2a612a13d..85c799cad321 100644 --- a/services/core/java/com/android/server/DisplayThread.java +++ b/services/core/java/com/android/server/DisplayThread.java @@ -40,7 +40,7 @@ public final class DisplayThread extends ServiceThread { if (sInstance == null) { sInstance = new DisplayThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); + sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java index 18fb4778c2a7..021bfaa10230 100644 --- a/services/core/java/com/android/server/FgThread.java +++ b/services/core/java/com/android/server/FgThread.java @@ -39,7 +39,7 @@ public final class FgThread extends ServiceThread { if (sInstance == null) { sInstance = new FgThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); + sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/services/core/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java index ad4c19485f26..bfe825a3a89e 100644 --- a/services/core/java/com/android/server/IoThread.java +++ b/services/core/java/com/android/server/IoThread.java @@ -36,7 +36,7 @@ public final class IoThread extends ServiceThread { if (sInstance == null) { sInstance = new IoThread(); sInstance.start(); - sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); + sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); sHandler = new Handler(sInstance.getLooper()); } } diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java index fd88d2609c25..f81307429ae0 100644 --- a/services/core/java/com/android/server/UiThread.java +++ b/services/core/java/com/android/server/UiThread.java @@ -47,7 +47,7 @@ public final class UiThread extends ServiceThread { sInstance = new UiThread(); sInstance.start(); final Looper looper = sInstance.getLooper(); - looper.setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER); + looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); looper.setSlowDispatchThresholdMs(SLOW_DISPATCH_THRESHOLD_MS); sHandler = new Handler(sInstance.getLooper()); } diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index b11b16e12c3a..2d2424fe7b59 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -65,6 +65,12 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { static final int POSITION_TOP = Integer.MAX_VALUE; static final int POSITION_BOTTOM = Integer.MIN_VALUE; + + /** + * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays. + */ + private static int sNextFreeStackId = 0; + private ActivityStackSupervisor mSupervisor; /** Actual Display this object tracks. */ int mDisplayId; @@ -231,6 +237,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return getOrCreateStack(windowingMode, activityType, onTop); } + private int getNextStackId() { + return sNextFreeStackId++; + } + /** * Creates a stack matching the input windowing mode and activity type on this display. * @param windowingMode The windowing mode the stack should be created in. If @@ -278,7 +288,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } } - final int stackId = mSupervisor.getNextStackId(); + final int stackId = getNextStackId(); return createStackUnchecked(windowingMode, activityType, stackId, onTop); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 52b18a8ef8f0..2ca2c27d0958 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -250,6 +250,7 @@ import android.app.assist.AssistStructure; import android.app.backup.IBackupManager; import android.app.servertransaction.ConfigurationChangeItem; import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; import android.content.ActivityNotFoundException; @@ -4522,9 +4523,18 @@ public class ActivityManagerService extends IActivityManager.Stub userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here. - return mActivityStartController.startActivityMayWait(caller, -1, callingPackage, - intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser"); + return mActivityStartController.obtainStarter(intent, "startActivityAsUser") + .setCaller(caller) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setResultTo(resultTo) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setStartFlags(startFlags) + .setProfilerInfo(profilerInfo) + .setMayWait(bOptions, userId) + .execute(); + } @Override @@ -4585,11 +4595,17 @@ public class ActivityManagerService extends IActivityManager.Stub // TODO: Switch to user app stacks here. try { - int ret = mActivityStartController.startActivityMayWait(null, targetUid, - targetPackage, intent, resolvedType, null, null, resultTo, resultWho, - requestCode, startFlags, null, null, null, bOptions, ignoreTargetSecurity, - userId, null, "startActivityAsCaller"); - return ret; + return mActivityStartController.obtainStarter(intent, "startActivityAsCaller") + .setCallingUid(targetUid) + .setCallingPackage(targetPackage) + .setResolvedType(resolvedType) + .setResultTo(resultTo) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setStartFlags(startFlags) + .setMayWait(bOptions, userId) + .setIgnoreTargetSecurity(ignoreTargetSecurity) + .execute(); } catch (SecurityException e) { // XXX need to figure out how to propagate to original app. // A SecurityException here is generally actually a fault of the original @@ -4615,9 +4631,18 @@ public class ActivityManagerService extends IActivityManager.Stub userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null); WaitResult res = new WaitResult(); // TODO: Switch to user app stacks here. - mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent, - resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - profilerInfo, res, null, bOptions, false, userId, null, "startActivityAndWait"); + mActivityStartController.obtainStarter(intent, "startActivityAndWait") + .setCaller(caller) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setResultTo(resultTo) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setStartFlags(startFlags) + .setMayWait(bOptions, userId) + .setProfilerInfo(profilerInfo) + .setWaitResult(res) + .execute(); return res; } @@ -4629,10 +4654,17 @@ public class ActivityManagerService extends IActivityManager.Stub userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null); // TODO: Switch to user app stacks here. - int ret = mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent, - resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null, null, - config, bOptions, false, userId, null, "startActivityWithConfig"); - return ret; + return mActivityStartController.obtainStarter(intent, "startActivityWithConfig") + .setCaller(caller) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setResultTo(resultTo) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setStartFlags(startFlags) + .setGlobalConfiguration(config) + .setMayWait(bOptions, userId) + .execute(); } @Override @@ -4678,9 +4710,16 @@ public class ActivityManagerService extends IActivityManager.Stub userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false, ALLOW_FULL_ONLY, "startVoiceActivity", null); // TODO: Switch to user app stacks here. - return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage, - intent, resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, - null, null, bOptions, false, userId, null, "startVoiceActivity"); + return mActivityStartController.obtainStarter(intent, "startVoiceActivity") + .setCallingUid(callingUid) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setVoiceSession(session) + .setVoiceInteractor(interactor) + .setStartFlags(startFlags) + .setProfilerInfo(profilerInfo) + .setMayWait(bOptions, userId) + .execute(); } @Override @@ -4689,9 +4728,13 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()"); userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false, ALLOW_FULL_ONLY, "startAssistantActivity", null); - return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage, - intent, resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions, - false, userId, null, "startAssistantActivity"); + + return mActivityStartController.obtainStarter(intent, "startAssistantActivity") + .setCallingUid(callingUid) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setMayWait(bOptions, userId) + .execute(); } @Override @@ -4731,9 +4774,12 @@ public class ActivityManagerService extends IActivityManager.Stub intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setComponent(recentsComponent); intent.putExtras(options); - return mActivityStartController.startActivityMayWait(null, recentsUid, - recentsPackage, intent, null, null, null, null, null, 0, 0, null, null, - null, activityOptions, false, userId, null, "startRecentsActivity"); + + return mActivityStartController.obtainStarter(intent, "startRecentsActivity") + .setCallingUid(recentsUid) + .setCallingPackage(recentsPackage) + .setMayWait(activityOptions, userId) + .execute(); } } finally { Binder.restoreCallingIdentity(origId); @@ -4906,11 +4952,22 @@ public class ActivityManagerService extends IActivityManager.Stub } final long origId = Binder.clearCallingIdentity(); - int res = mActivityStartController.startActivity(r.app.thread, intent, - null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null, - null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1, - r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options, - false, false, null, null, "startNextMatchingActivity"); + // TODO(b/64750076): Check if calling pid should really be -1. + final int res = mActivityStartController + .obtainStarter(intent, "startNextMatchingActivity") + .setCaller(r.app.thread) + .setResolvedType(r.resolvedType) + .setActivityInfo(aInfo) + .setResultTo(resultTo != null ? resultTo.appToken : null) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setCallingPid(-1) + .setCallingUid(r.launchedFromUid) + .setCallingPackage(r.launchedFromPackage) + .setRealCallingPid(-1) + .setRealCallingUid(r.launchedFromUid) + .setActivityOptions(options) + .execute(); Binder.restoreCallingIdentity(origId); r.finishing = wasFinishing; @@ -9964,7 +10021,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - TaskRecord task = new TaskRecord(this, + TaskRecord task = TaskRecord.create(this, mStackSupervisor.getNextTaskIdForUserLocked(r.userId), ainfo, intent, description); if (!mRecentTasks.addToBottom(task)) { @@ -20168,6 +20225,11 @@ public class ActivityManagerService extends IActivityManager.Stub // Instrumentation can kill and relaunch even persistent processes forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId, "start instr"); + // Inform usage stats to make the target package active + if (mUsageStatsService != null) { + mUsageStatsService.reportEvent(ii.targetPackage, userId, + UsageEvents.Event.SYSTEM_INTERACTION); + } ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride); app.instr = activeInstr; activeInstr.mFinished = false; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index af4d3f8e4ba2..edf9813497e0 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3899,12 +3899,19 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( destIntent.getComponent(), 0, srec.userId); - int res = mService.getActivityStartController().startActivity( - srec.app.thread, destIntent, null /*ephemeralIntent*/, null, aInfo, - null /*rInfo*/, null, null, parent.appToken, null, 0, -1, - parent.launchedFromUid, parent.launchedFromPackage, -1, - parent.launchedFromUid, 0, null, false, true, null, null, - "navigateUpTo"); + // TODO(b/64750076): Check if calling pid should really be -1. + final int res = mService.getActivityStartController() + .obtainStarter(destIntent, "navigateUpTo") + .setCaller(srec.app.thread) + .setActivityInfo(aInfo) + .setResultTo(parent.appToken) + .setCallingPid(-1) + .setCallingUid(parent.launchedFromUid) + .setCallingPackage(parent.launchedFromPackage) + .setRealCallingPid(-1) + .setRealCallingUid(parent.launchedFromUid) + .setComponentSpecified(true) + .execute(); foundParentInTask = res == ActivityManager.START_SUCCESS; } catch (RemoteException e) { foundParentInTask = false; @@ -5015,8 +5022,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity, ActivityRecord source, ActivityOptions options) { - final TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession, - voiceInteractor); + final TaskRecord task = TaskRecord.create( + mService, taskId, info, intent, voiceSession, voiceInteractor); // add the task to stack first, mTaskPositioner might need the stack association addTask(task, toTop, "createTaskRecord"); final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController() diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 48c08a5718b9..cd3b21c63ad6 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -298,9 +298,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private LaunchingBoundsController mLaunchingBoundsController; - /** Counter for next free stack ID to use for dynamic activity stacks. */ - private int mNextFreeStackId = 0; - /** * Maps the task identifier that activities are currently being started in to the userId of the * task. Each time a new task is created, the entry for the userId of the task is incremented @@ -2904,16 +2901,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - int getNextStackId() { - while (true) { - if (getStack(mNextFreeStackId) == null) { - break; - } - mNextFreeStackId++; - } - return mNextFreeStackId; - } - /** * Called to restore the state of the task into the stack that it's supposed to go into. * diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index 317a68f9b09c..a97b93ca01ba 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -25,8 +25,6 @@ import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.ProfilerInfo; -import android.app.WaitResult; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Intent; @@ -34,7 +32,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Configuration; import android.os.Binder; import android.os.Bundle; import android.os.FactoryTest; @@ -43,12 +40,10 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.provider.Settings; -import android.service.voice.IVoiceInteractionSession; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; -import com.android.internal.app.IVoiceInteractor; import com.android.server.am.ActivityStarter.DefaultFactory; import com.android.server.am.ActivityStarter.Factory; @@ -72,7 +67,6 @@ public class ActivityStartController { private final ActivityManagerService mService; private final ActivityStackSupervisor mSupervisor; - private final ActivityStartInterceptor mInterceptor; /** Last home activity record we attempted to start. */ private ActivityRecord mLastHomeActivityStartRecord; @@ -115,7 +109,9 @@ public class ActivityStartController { private ActivityStarter mLastStarter; ActivityStartController(ActivityManagerService service) { - this(service, service.mStackSupervisor, new DefaultFactory()); + this(service, service.mStackSupervisor, + new DefaultFactory(service, service.mStackSupervisor, + new ActivityStartInterceptor(service, service.mStackSupervisor))); } @VisibleForTesting @@ -124,38 +120,20 @@ public class ActivityStartController { mService = service; mSupervisor = supervisor; mHandler = new StartHandler(mService.mHandlerThread.getLooper()); - mInterceptor = new ActivityStartInterceptor(mService, mSupervisor); mFactory = factory; + mFactory.setController(this); } /** - * Retrieves a starter to be used for a new start request. The starter will be added to the - * active starters list. - * - * TODO(b/64750076): This should be removed when {@link #obtainStarter} is implemented. At that - * time, {@link ActivityStarter#execute} will be able to handle cleaning up the starter's - * internal references. + * @return A starter to configure and execute starting an activity. It is valid until after + * {@link ActivityStarter#execute} is invoked. At that point, the starter should be + * considered invalid and no longer modified or used. */ - private ActivityStarter createStarter() { - mLastStarter = mFactory.getStarter(this, mService, mService.mStackSupervisor, mInterceptor); - return mLastStarter; - } + ActivityStarter obtainStarter(Intent intent, String reason) { + final ActivityStarter starter = mFactory.obtainStarter(); + mLastStarter = starter; - /** - * TODO(b/64750076): Remove once we directly expose starter interface to callers through - * {@link #obtainStarter}. - */ - int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, - String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, - String callingPackage, int realCallingPid, int realCallingUid, int startFlags, - ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, - ActivityRecord[] outActivity, TaskRecord inTask, String reason) { - return createStarter().startActivityLocked(caller, intent, ephemeralIntent, resolvedType, - aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, - callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, - options, ignoreTargetSecurity, componentSpecified, outActivity, inTask, reason); + return starter.setIntent(intent).setReason(reason); } /** @@ -170,18 +148,12 @@ public class ActivityStartController { void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(reason); - final ActivityStarter starter = createStarter(); - - mLastHomeActivityStartResult = starter.startActivityLocked(null /*caller*/, intent, - null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/, - null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/, - null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, - null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/, - 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/, - false /*componentSpecified*/, tmpOutRecord, null /*inTask*/, - "startHomeActivity: " + reason); + mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) + .setOutActivity(tmpOutRecord) + .setCallingUid(0) + .setActivityInfo(aInfo) + .execute(); mLastHomeActivityStartRecord = tmpOutRecord[0]; - if (mSupervisor.inResumeTopActivity) { // If we are in resume section already, home activity will be initialized, but not // resumed (to avoid recursive resume) and will stay that way until something pokes it @@ -228,9 +200,10 @@ public class ActivityStartController { intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setComponent(new ComponentName( ri.activityInfo.packageName, ri.activityInfo.name)); - startActivity(null, intent, null /*ephemeralIntent*/, null, ri.activityInfo, - null /*rInfo*/, null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, - false, false, null, null, "startSetupActivity"); + obtainStarter(intent, "startSetupActivity") + .setCallingUid(0) + .setActivityInfo(ri.activityInfo) + .execute(); } } } @@ -246,9 +219,17 @@ public class ActivityStartController { null); // TODO: Switch to user app stacks here. - return startActivityMayWait(null, uid, callingPackage, - intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - null, null, null, bOptions, false, userId, inTask, reason); + return obtainStarter(intent, reason) + .setCallingUid(uid) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setResultTo(resultTo) + .setResultWho(resultWho) + .setRequestCode(requestCode) + .setStartFlags(startFlags) + .setMayWait(bOptions, userId) + .setInTask(inTask) + .execute(); } final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, @@ -262,24 +243,6 @@ public class ActivityStartController { return ret; } - /** - * TODO(b/64750076): Remove once we directly expose starter interface to callers through - * {@link #obtainStarter}. - */ - int startActivityMayWait(IApplicationThread caller, int callingUid, - String callingPackage, Intent intent, String resolvedType, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - IBinder resultTo, String resultWho, int requestCode, int startFlags, - ProfilerInfo profilerInfo, WaitResult outResult, - Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId, - TaskRecord inTask, String reason) { - return createStarter().startActivityMayWait(caller, callingUid, callingPackage, intent, - resolvedType, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, - startFlags, profilerInfo, outResult, globalConfig, bOptions, - ignoreTargetSecurity, - userId, inTask, reason); - } - int startActivities(IApplicationThread caller, int callingUid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId, String reason) { @@ -340,11 +303,23 @@ public class ActivityStartController { ActivityOptions options = ActivityOptions.fromBundle( i == intents.length - 1 ? bOptions : null); - int res = startActivity(caller, intent, null /*ephemeralIntent*/, - resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1, - callingPid, callingUid, callingPackage, - realCallingPid, realCallingUid, 0, - options, false, componentSpecified, outActivity, null, reason); + + final int res = obtainStarter(intent, reason) + .setCaller(caller) + .setResolvedType(resolvedTypes[i]) + .setActivityInfo(aInfo) + .setResultTo(resultTo) + .setRequestCode(-1) + .setCallingPid(callingPid) + .setCallingUid(callingUid) + .setCallingPackage(callingPackage) + .setRealCallingPid(realCallingPid) + .setRealCallingUid(realCallingUid) + .setActivityOptions(options) + .setComponentSpecified(componentSpecified) + .setOutActivity(outActivity) + .execute(); + if (res < 0) { return res; } @@ -369,10 +344,11 @@ public class ActivityStartController { while (!mPendingActivityLaunches.isEmpty()) { final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0); final boolean resume = doResume && mPendingActivityLaunches.isEmpty(); - final ActivityStarter starter = createStarter(); + final ActivityStarter starter = obtainStarter(null /* intent */, + "pendingActivityLaunch"); try { - starter.startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, - null, null, null /*outRecords*/); + starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, + resume, null, null, null /* outRecords */); } catch (Exception e) { Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); pal.sendErrorResult(e.getMessage()); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 3bee4228d9fb..dda8e9c18229 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -74,7 +74,6 @@ import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IApplicationThread; @@ -87,7 +86,6 @@ import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.AuxiliaryResolveInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; @@ -186,6 +184,13 @@ class ActivityStarter { // The reason we were trying to start the last activity private String mLastStartReason; + /* + * Request details provided through setter methods. Should be reset after {@link #execute()} + * to avoid unnecessarily retaining parameters. Note that the request is ignored when + * {@link #startResolvedActivity} is invoked directly. + */ + private Request mRequest = new Request(); + /** * An interface that to provide {@link ActivityStarter} instances to the controller. This is * used by tests to inject their own starter implementations for verification purposes. @@ -193,29 +198,98 @@ class ActivityStarter { @VisibleForTesting interface Factory { /** + * Sets the {@link ActivityStartController} to be passed to {@link ActivityStarter}. + */ + void setController(ActivityStartController controller); + + /** * Generates an {@link ActivityStarter} that is ready to handle a new start request. * @param controller The {@link ActivityStartController} which the starter who will own * this instance. * @return an {@link ActivityStarter} */ - ActivityStarter getStarter(ActivityStartController controller, - ActivityManagerService service, ActivityStackSupervisor supervisor, - ActivityStartInterceptor interceptor); + ActivityStarter obtainStarter(); } /** * Default implementation of {@link StarterFactory}. */ static class DefaultFactory implements Factory { + private ActivityStartController mController; + private ActivityManagerService mService; + private ActivityStackSupervisor mSupervisor; + private ActivityStartInterceptor mInterceptor; + + DefaultFactory(ActivityManagerService service, + ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) { + mService = service; + mSupervisor = supervisor; + mInterceptor = interceptor; + } + + @Override + public void setController(ActivityStartController controller) { + mController = controller; + } + @Override - public ActivityStarter getStarter(ActivityStartController controller, - ActivityManagerService service, ActivityStackSupervisor supervisor, - ActivityStartInterceptor interceptor) { + public ActivityStarter obtainStarter() { // TODO(b/64750076): Investigate recycling instances to reduce object creation overhead. - return new ActivityStarter(controller, service, supervisor, interceptor); + return new ActivityStarter(mController, mService, mSupervisor, mInterceptor); } } + /** + * Container for capturing initial start request details. This information is NOT reset until + * the {@link ActivityStarter} is recycled, allowing for multiple invocations with the same + * parameters. + * + * TODO(b/64750076): Investigate consolidating member variables of {@link ActivityStarter} with + * the request object. Note that some member variables are referenced in + * {@link #dump(PrintWriter, String)} and therefore cannot be cleared immediately after + * execution. + */ + private static class Request { + private static final int DEFAULT_CALLING_UID = -1; + private static final int DEFAULT_CALLING_PID = 0; + + IApplicationThread caller; + Intent intent; + Intent ephemeralIntent; + String resolvedType; + ActivityInfo activityInfo; + ResolveInfo resolveInfo; + IVoiceInteractionSession voiceSession; + IVoiceInteractor voiceInteractor; + IBinder resultTo; + String resultWho; + int requestCode; + int callingPid = DEFAULT_CALLING_UID; + int callingUid = DEFAULT_CALLING_PID; + String callingPackage; + int realCallingPid; + int realCallingUid; + int startFlags; + ActivityOptions activityOptions; + boolean ignoreTargetSecurity; + boolean componentSpecified; + ActivityRecord[] outActivity; + TaskRecord inTask; + String reason; + ProfilerInfo profilerInfo; + Configuration globalConfig; + Bundle waitOptions; + int userId; + WaitResult waitResult; + + /** + * Indicates that we should wait for the result of the start request. This flag is set when + * {@link ActivityStarter#setMayWait(Bundle, int)} is called. + * {@see ActivityStarter#startActivityMayWait}. + */ + boolean mayWait; + } + ActivityStarter(ActivityStartController controller, ActivityManagerService service, ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) { mController = controller; @@ -224,14 +298,44 @@ class ActivityStarter { mInterceptor = interceptor; } + ActivityRecord getStartActivity() { + return mStartActivity; + } + boolean relatedToPackage(String packageName) { return (mLastStartActivityRecord[0] != null - && packageName.equals(mLastStartActivityRecord[0].packageName)) - || (mStartActivity != null - && packageName.equals(mStartActivity.packageName)); + && packageName.equals(mLastStartActivityRecord[0].packageName)) + || (mStartActivity != null && packageName.equals(mStartActivity.packageName)); + } + + /** + * Starts an activity based on the request parameters provided earlier. + * @return The starter result. + */ + int execute() { + // TODO(b/64750076): Look into passing request directly to these methods to allow + // for transactional diffs and preprocessing. + if (mRequest.mayWait) { + return startActivityMayWait(mRequest.caller, mRequest.callingUid, + mRequest.callingPackage, mRequest.intent, mRequest.resolvedType, + mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, + mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, + mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, + mRequest.waitOptions, mRequest.ignoreTargetSecurity, mRequest.userId, + mRequest.inTask, mRequest.reason); + } else { + return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, + mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, + mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, + mRequest.resultWho, mRequest.requestCode, mRequest.callingPid, + mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, + mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, + mRequest.ignoreTargetSecurity, mRequest.componentSpecified, + mRequest.outActivity, mRequest.inTask, mRequest.reason); + } } - int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent, + private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, @@ -265,7 +369,6 @@ class ActivityStarter { return result != START_ABORTED ? result : START_SUCCESS; } - /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */ private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, @@ -548,8 +651,8 @@ class ActivityStarter { mController.doPendingActivityLaunches(false); - return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, - options, inTask, outActivity); + return startResolvedActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, + true /* doResume */, options, inTask, outActivity); } /** @@ -569,7 +672,8 @@ class ActivityStarter { auxiliaryResponse.failureIntent, callingPackage, verificationBundle, resolvedType, userId, auxiliaryResponse.packageName, auxiliaryResponse.splitName, auxiliaryResponse.installFailureActivity, auxiliaryResponse.versionCode, - auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo); + auxiliaryResponse.token, auxiliaryResponse.resolveInfo.getExtras(), + auxiliaryResponse.needsPhaseTwo); } void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) { @@ -610,7 +714,7 @@ class ActivityStarter { } } - final int startActivityMayWait(IApplicationThread caller, int callingUid, + private int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, @@ -754,7 +858,7 @@ class ActivityStarter { } final ActivityRecord[] outRecord = new ActivityRecord[1]; - int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType, + int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, @@ -820,10 +924,16 @@ class ActivityStarter { } } - int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, - ActivityRecord[] outActivity) { + /** + * Starts an activity based on the provided {@link ActivityRecord} and environment parameters. + * Note that this method is called internally as well as part of {@link #startActivity}. + * + * @return The start result. + */ + int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord, + IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, + int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, + ActivityRecord[] outActivity) { int result = START_CANCELED; try { mService.mWindowManager.deferSurfaceLayout(); @@ -2008,6 +2118,155 @@ class ActivityStarter { (flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0; } + ActivityStarter setIntent(Intent intent) { + mRequest.intent = intent; + return this; + } + + ActivityStarter setReason(String reason) { + mRequest.reason = reason; + return this; + } + + ActivityStarter setCaller(IApplicationThread caller) { + mRequest.caller = caller; + return this; + } + + ActivityStarter setEphemeralIntent(Intent intent) { + mRequest.ephemeralIntent = intent; + return this; + } + + + ActivityStarter setResolvedType(String type) { + mRequest.resolvedType = type; + return this; + } + + ActivityStarter setActivityInfo(ActivityInfo info) { + mRequest.activityInfo = info; + return this; + } + + ActivityStarter setResolveInfo(ResolveInfo info) { + mRequest.resolveInfo = info; + return this; + } + + ActivityStarter setVoiceSession(IVoiceInteractionSession voiceSession) { + mRequest.voiceSession = voiceSession; + return this; + } + + ActivityStarter setVoiceInteractor(IVoiceInteractor voiceInteractor) { + mRequest.voiceInteractor = voiceInteractor; + return this; + } + + ActivityStarter setResultTo(IBinder resultTo) { + mRequest.resultTo = resultTo; + return this; + } + + ActivityStarter setResultWho(String resultWho) { + mRequest.resultWho = resultWho; + return this; + } + + ActivityStarter setRequestCode(int requestCode) { + mRequest.requestCode = requestCode; + return this; + } + + ActivityStarter setCallingPid(int pid) { + mRequest.callingPid = pid; + return this; + } + + ActivityStarter setCallingUid(int uid) { + mRequest.callingUid = uid; + return this; + } + + ActivityStarter setCallingPackage(String callingPackage) { + mRequest.callingPackage = callingPackage; + return this; + } + + ActivityStarter setRealCallingPid(int pid) { + mRequest.realCallingPid = pid; + return this; + } + + ActivityStarter setRealCallingUid(int uid) { + mRequest.realCallingUid = uid; + return this; + } + + ActivityStarter setStartFlags(int startFlags) { + mRequest.startFlags = startFlags; + return this; + } + + ActivityStarter setActivityOptions(ActivityOptions options) { + mRequest.activityOptions = options; + return this; + } + + ActivityStarter setIgnoreTargetSecurity(boolean ignoreTargetSecurity) { + mRequest.ignoreTargetSecurity = ignoreTargetSecurity; + return this; + } + + ActivityStarter setComponentSpecified(boolean componentSpecified) { + mRequest.componentSpecified = componentSpecified; + return this; + } + + ActivityStarter setOutActivity(ActivityRecord[] outActivity) { + mRequest.outActivity = outActivity; + return this; + } + + ActivityStarter setInTask(TaskRecord inTask) { + mRequest.inTask = inTask; + return this; + } + + ActivityStarter setWaitResult(WaitResult result) { + mRequest.waitResult = result; + return this; + } + + ActivityStarter setProfilerInfo(ProfilerInfo info) { + mRequest.profilerInfo = info; + return this; + } + + ActivityStarter setGlobalConfiguration(Configuration config) { + mRequest.globalConfig = config; + return this; + } + + ActivityStarter setWaitOptions(Bundle options) { + mRequest.waitOptions = options; + return this; + } + + ActivityStarter setUserId(int userId) { + mRequest.userId = userId; + return this; + } + + ActivityStarter setMayWait(Bundle options, int userId) { + mRequest.mayWait = true; + mRequest.waitOptions = options; + mRequest.userId = userId; + + return this; + } + void dump(PrintWriter pw, String prefix) { prefix = prefix + " "; pw.print(prefix); diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java index e5872c0337cf..f821f6bdb925 100644 --- a/services/core/java/com/android/server/am/AppTaskImpl.java +++ b/services/core/java/com/android/server/am/AppTaskImpl.java @@ -122,9 +122,14 @@ class AppTaskImpl extends IAppTask.Stub { throw new IllegalArgumentException("Bad app thread " + appThread); } } - return mService.getActivityStartController().startActivityMayWait(appThread, -1, - callingPackage, intent, resolvedType, null, null, null, null, 0, 0, null, null, - null, bOptions, false, callingUser, tr, "AppTaskImpl"); + + return mService.getActivityStartController().obtainStarter(intent, "AppTaskImpl") + .setCaller(appThread) + .setCallingPackage(callingPackage) + .setResolvedType(resolvedType) + .setMayWait(bOptions, callingUser) + .setInTask(tr) + .execute(); } @Override diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index d77e1a20e0c0..ba3e25aea66c 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -22,8 +22,10 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.STATUS_BAR_SERVICE; +import static android.content.Intent.ACTION_CALL_EMERGENCY; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; +import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; @@ -45,6 +47,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.os.Binder; import android.os.Debug; import android.os.Handler; @@ -52,9 +55,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telecom.TelecomManager; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; @@ -133,6 +138,8 @@ public class LockTaskController { WindowManagerService mWindowManager; @VisibleForTesting LockPatternUtils mLockPatternUtils; + @VisibleForTesting + TelecomManager mTelecomManager; /** * Helper that is responsible for showing the right toast when a disallowed activity operation @@ -165,7 +172,7 @@ public class LockTaskController { /** * Features that are allowed by DPC to show during LockTask mode. */ - private final SparseArray<Integer> mLockTaskFeatures = new SparseArray<>(); + private final SparseIntArray mLockTaskFeatures = new SparseIntArray(); /** * Store the current lock task mode. Possible values: @@ -298,6 +305,11 @@ public class LockTaskController { return false; } + // Allow emergency calling when the device is protected by a locked keyguard + if (isKeyguardAllowed(task.userId) && isEmergencyCallTask(task)) { + return false; + } + return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty()); } @@ -306,6 +318,37 @@ public class LockTaskController { & DevicePolicyManager.LOCK_TASK_FEATURE_RECENTS) != 0; } + private boolean isKeyguardAllowed(int userId) { + return (getLockTaskFeaturesForUser(userId) + & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0; + } + + private boolean isEmergencyCallTask(TaskRecord task) { + final Intent intent = task.intent; + if (intent == null) { + return false; + } + + // 1. The emergency keypad activity launched on top of the keyguard + if (EMERGENCY_DIALER_COMPONENT.equals(intent.getComponent())) { + return true; + } + + // 2. The intent sent by the keypad, which is handled by Telephony + if (ACTION_CALL_EMERGENCY.equals(intent.getAction())) { + return true; + } + + // 3. Telephony then starts the default package for making the call + final TelecomManager tm = getTelecomManager(); + final String dialerPackage = tm != null ? tm.getSystemDialerPackage() : null; + if (dialerPackage != null && dialerPackage.equals(intent.getComponent().getPackageName())) { + return true; + } + + return false; + } + /** * Stop the current lock task mode. * @@ -686,11 +729,10 @@ public class LockTaskController { mWindowManager.reenableKeyguard(mToken); } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) { - int lockTaskFeatures = getLockTaskFeaturesForUser(userId); - if ((DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD & lockTaskFeatures) == 0) { - mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG); - } else { + if (isKeyguardAllowed(userId)) { mWindowManager.reenableKeyguard(mToken); + } else { + mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG); } } else { // lockTaskModeState == LOCK_TASK_MODE_PINNED @@ -784,6 +826,15 @@ public class LockTaskController { return mLockPatternUtils; } + @Nullable + private TelecomManager getTelecomManager() { + if (mTelecomManager == null) { + // We don't preserve the TelecomManager object to save memory + return mContext.getSystemService(TelecomManager.class); + } + return mTelecomManager; + } + // Should only be called on the handler thread @NonNull private LockTaskNotify getLockTaskNotify() { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 83965ee497c8..48737a54cadc 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -193,6 +193,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // Do not move the stack as a part of reparenting static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; + /** + * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}. + */ + private static TaskRecordFactory sTaskRecordFactory; + final int taskId; // Unique identifier for this task. String affinity; // The affinity name for this task, or null; may change identity. String rootAffinity; // Initial base affinity, or null; does not change from initial root. @@ -312,6 +317,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi private TaskWindowContainerController mWindowContainerController; + /** + * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo, + * Intent, TaskDescription)} instead. + */ TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { mService = service; @@ -331,6 +340,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); } + /** + * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo, + * Intent, IVoiceInteractionSession, IVoiceInteractor)} instead. + */ TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, TaskDescription _taskDescription) { mService = service; @@ -357,7 +370,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); } - private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, + /** + * Don't use constructor directly. This is only used by XML parser. + */ + TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, @@ -1632,278 +1648,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi updateTaskDescription(); } - void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { - if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); - - out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); - if (realActivity != null) { - out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); - } - out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); - if (origActivity != null) { - out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); - } - // Write affinity, and root affinity if it is different from affinity. - // We use the special string "@" for a null root affinity, so we can identify - // later whether we were given a root affinity or should just make it the - // same as the affinity. - if (affinity != null) { - out.attribute(null, ATTR_AFFINITY, affinity); - if (!affinity.equals(rootAffinity)) { - out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); - } - } else if (rootAffinity != null) { - out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); - } - out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); - out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); - out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); - out.attribute(null, ATTR_USERID, String.valueOf(userId)); - out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); - out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); - out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); - out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); - if (lastDescription != null) { - out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); - } - if (lastTaskDescription != null) { - lastTaskDescription.saveToXml(out); - } - out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); - out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); - out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); - out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); - out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); - out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); - out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); - out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, - String.valueOf(mSupportsPictureInPicture)); - if (mLastNonFullscreenBounds != null) { - out.attribute( - null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); - } - out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); - out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); - out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION)); - - if (affinityIntent != null) { - out.startTag(null, TAG_AFFINITYINTENT); - affinityIntent.saveToXml(out); - out.endTag(null, TAG_AFFINITYINTENT); - } - - out.startTag(null, TAG_INTENT); - intent.saveToXml(out); - out.endTag(null, TAG_INTENT); - - final ArrayList<ActivityRecord> activities = mActivities; - final int numActivities = activities.size(); - for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || - ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT - | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && - activityNdx > 0) { - // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). - break; - } - out.startTag(null, TAG_ACTIVITY); - r.saveToXml(out); - out.endTag(null, TAG_ACTIVITY); - } - } - - static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) - throws IOException, XmlPullParserException { - Intent intent = null; - Intent affinityIntent = null; - ArrayList<ActivityRecord> activities = new ArrayList<>(); - ComponentName realActivity = null; - boolean realActivitySuspended = false; - ComponentName origActivity = null; - String affinity = null; - String rootAffinity = null; - boolean hasRootAffinity = false; - boolean rootHasReset = false; - boolean autoRemoveRecents = false; - boolean askedCompatMode = false; - int taskType = 0; - int userId = 0; - boolean userSetupComplete = true; - int effectiveUid = -1; - String lastDescription = null; - long lastTimeOnTop = 0; - boolean neverRelinquishIdentity = true; - int taskId = INVALID_TASK_ID; - final int outerDepth = in.getDepth(); - TaskDescription taskDescription = new TaskDescription(); - int taskAffiliation = INVALID_TASK_ID; - int taskAffiliationColor = 0; - int prevTaskId = INVALID_TASK_ID; - int nextTaskId = INVALID_TASK_ID; - int callingUid = -1; - String callingPackage = ""; - int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; - boolean supportsPictureInPicture = false; - Rect bounds = null; - int minWidth = INVALID_MIN_SIZE; - int minHeight = INVALID_MIN_SIZE; - int persistTaskVersion = 0; - - for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { - final String attrName = in.getAttributeName(attrNdx); - final String attrValue = in.getAttributeValue(attrNdx); - if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + - attrName + " value=" + attrValue); - if (ATTR_TASKID.equals(attrName)) { - if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); - } else if (ATTR_REALACTIVITY.equals(attrName)) { - realActivity = ComponentName.unflattenFromString(attrValue); - } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) { - realActivitySuspended = Boolean.valueOf(attrValue); - } else if (ATTR_ORIGACTIVITY.equals(attrName)) { - origActivity = ComponentName.unflattenFromString(attrValue); - } else if (ATTR_AFFINITY.equals(attrName)) { - affinity = attrValue; - } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { - rootAffinity = attrValue; - hasRootAffinity = true; - } else if (ATTR_ROOTHASRESET.equals(attrName)) { - rootHasReset = Boolean.parseBoolean(attrValue); - } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { - autoRemoveRecents = Boolean.parseBoolean(attrValue); - } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { - askedCompatMode = Boolean.parseBoolean(attrValue); - } else if (ATTR_USERID.equals(attrName)) { - userId = Integer.parseInt(attrValue); - } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) { - userSetupComplete = Boolean.parseBoolean(attrValue); - } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { - effectiveUid = Integer.parseInt(attrValue); - } else if (ATTR_TASKTYPE.equals(attrName)) { - taskType = Integer.parseInt(attrValue); - } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { - lastDescription = attrValue; - } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { - lastTimeOnTop = Long.parseLong(attrValue); - } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { - neverRelinquishIdentity = Boolean.parseBoolean(attrValue); - } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { - taskDescription.restoreFromXml(attrName, attrValue); - } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { - taskAffiliation = Integer.parseInt(attrValue); - } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { - prevTaskId = Integer.parseInt(attrValue); - } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { - nextTaskId = Integer.parseInt(attrValue); - } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { - taskAffiliationColor = Integer.parseInt(attrValue); - } else if (ATTR_CALLING_UID.equals(attrName)) { - callingUid = Integer.parseInt(attrValue); - } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { - callingPackage = attrValue; - } else if (ATTR_RESIZE_MODE.equals(attrName)) { - resizeMode = Integer.parseInt(attrValue); - } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) { - supportsPictureInPicture = Boolean.parseBoolean(attrValue); - } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { - bounds = Rect.unflattenFromString(attrValue); - } else if (ATTR_MIN_WIDTH.equals(attrName)) { - minWidth = Integer.parseInt(attrValue); - } else if (ATTR_MIN_HEIGHT.equals(attrName)) { - minHeight = Integer.parseInt(attrValue); - } else if (ATTR_PERSIST_TASK_VERSION.equals(attrName)) { - persistTaskVersion = Integer.parseInt(attrValue); - } else { - Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); - } - } - - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { - if (event == XmlPullParser.START_TAG) { - final String name = in.getName(); - if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + - name); - if (TAG_AFFINITYINTENT.equals(name)) { - affinityIntent = Intent.restoreFromXml(in); - } else if (TAG_INTENT.equals(name)) { - intent = Intent.restoreFromXml(in); - } else if (TAG_ACTIVITY.equals(name)) { - ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor); - if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + - activity); - if (activity != null) { - activities.add(activity); - } - } else { - Slog.e(TAG, "restoreTask: Unexpected name=" + name); - XmlUtils.skipCurrentTag(in); - } - } - } - if (!hasRootAffinity) { - rootAffinity = affinity; - } else if ("@".equals(rootAffinity)) { - rootAffinity = null; - } - if (effectiveUid <= 0) { - Intent checkIntent = intent != null ? intent : affinityIntent; - effectiveUid = 0; - if (checkIntent != null) { - IPackageManager pm = AppGlobals.getPackageManager(); - try { - ApplicationInfo ai = pm.getApplicationInfo( - checkIntent.getComponent().getPackageName(), - PackageManager.MATCH_UNINSTALLED_PACKAGES - | PackageManager.MATCH_DISABLED_COMPONENTS, userId); - if (ai != null) { - effectiveUid = ai.uid; - } - } catch (RemoteException e) { - } - } - Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent - + ": effectiveUid=" + effectiveUid); - } - - if (persistTaskVersion < 1) { - // We need to convert the resize mode of home activities saved before version one if - // they are marked as RESIZE_MODE_RESIZEABLE to RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION - // since we didn't have that differentiation before version 1 and the system didn't - // resize home activities before then. - if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { - resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; - } - } else { - // This activity has previously marked itself explicitly as both resizeable and - // supporting picture-in-picture. Since there is no longer a requirement for - // picture-in-picture activities to be resizeable, we can mark this simply as - // resizeable and supporting picture-in-picture separately. - if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { - resizeMode = RESIZE_MODE_RESIZEABLE; - supportsPictureInPicture = true; - } - } - - final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, - affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, - autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, - activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, - taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, - callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, - userSetupComplete, minWidth, minHeight); - task.updateOverrideConfiguration(bounds); - - for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { - activities.get(activityNdx).setTask(task); - } - - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); - return task; - } - private void adjustForMinimalTaskDimensions(Rect bounds) { if (bounds == null) { return; @@ -2320,4 +2064,382 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi top = base = null; } } + + /** + * Saves this {@link TaskRecord} to XML using given serializer. + */ + void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { + if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); + + out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); + if (realActivity != null) { + out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); + } + out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); + if (origActivity != null) { + out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); + } + // Write affinity, and root affinity if it is different from affinity. + // We use the special string "@" for a null root affinity, so we can identify + // later whether we were given a root affinity or should just make it the + // same as the affinity. + if (affinity != null) { + out.attribute(null, ATTR_AFFINITY, affinity); + if (!affinity.equals(rootAffinity)) { + out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); + } + } else if (rootAffinity != null) { + out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); + } + out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); + out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); + out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); + out.attribute(null, ATTR_USERID, String.valueOf(userId)); + out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); + out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); + out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); + out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); + if (lastDescription != null) { + out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); + } + if (lastTaskDescription != null) { + lastTaskDescription.saveToXml(out); + } + out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); + out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); + out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); + out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); + out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); + out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); + out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); + out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, + String.valueOf(mSupportsPictureInPicture)); + if (mLastNonFullscreenBounds != null) { + out.attribute( + null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); + } + out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); + out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); + out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION)); + + if (affinityIntent != null) { + out.startTag(null, TAG_AFFINITYINTENT); + affinityIntent.saveToXml(out); + out.endTag(null, TAG_AFFINITYINTENT); + } + + out.startTag(null, TAG_INTENT); + intent.saveToXml(out); + out.endTag(null, TAG_INTENT); + + final ArrayList<ActivityRecord> activities = mActivities; + final int numActivities = activities.size(); + for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || + ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT + | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && + activityNdx > 0) { + // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). + break; + } + out.startTag(null, TAG_ACTIVITY); + r.saveToXml(out); + out.endTag(null, TAG_ACTIVITY); + } + } + + @VisibleForTesting + static TaskRecordFactory getTaskRecordFactory() { + if (sTaskRecordFactory == null) { + setTaskRecordFactory(new TaskRecordFactory()); + } + return sTaskRecordFactory; + } + + static void setTaskRecordFactory(TaskRecordFactory factory) { + sTaskRecordFactory = factory; + } + + static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor) { + return getTaskRecordFactory().create( + service, taskId, info, intent, voiceSession, voiceInteractor); + } + + static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, TaskDescription taskDescription) { + return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription); + } + + static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) + throws IOException, XmlPullParserException { + return getTaskRecordFactory().restoreFromXml(in, stackSupervisor); + } + + /** + * A factory class used to create {@link TaskRecord} or its subclass if any. This can be + * specified when system boots by setting it with + * {@link #setTaskRecordFactory(TaskRecordFactory)}. + */ + static class TaskRecordFactory { + + TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor) { + return new TaskRecord( + service, taskId, info, intent, voiceSession, voiceInteractor); + } + + TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, TaskDescription taskDescription) { + return new TaskRecord(service, taskId, info, intent, taskDescription); + } + + /** + * Should only be used when we're restoring {@link TaskRecord} from storage. + */ + TaskRecord create(ActivityManagerService service, int taskId, Intent intent, + Intent affinityIntent, String affinity, String rootAffinity, + ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, + boolean autoRemoveRecents, boolean askedCompatMode, int userId, + int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, + long lastTimeMoved, boolean neverRelinquishIdentity, + TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, + int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, + int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, + boolean userSetupComplete, int minWidth, int minHeight) { + return new TaskRecord(service, taskId, intent, affinityIntent, affinity, + rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents, + askedCompatMode, userId, effectiveUid, lastDescription, activities, + lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation, + prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, + resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete, + minWidth, minHeight); + } + + TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) + throws IOException, XmlPullParserException { + Intent intent = null; + Intent affinityIntent = null; + ArrayList<ActivityRecord> activities = new ArrayList<>(); + ComponentName realActivity = null; + boolean realActivitySuspended = false; + ComponentName origActivity = null; + String affinity = null; + String rootAffinity = null; + boolean hasRootAffinity = false; + boolean rootHasReset = false; + boolean autoRemoveRecents = false; + boolean askedCompatMode = false; + int taskType = 0; + int userId = 0; + boolean userSetupComplete = true; + int effectiveUid = -1; + String lastDescription = null; + long lastTimeOnTop = 0; + boolean neverRelinquishIdentity = true; + int taskId = INVALID_TASK_ID; + final int outerDepth = in.getDepth(); + TaskDescription taskDescription = new TaskDescription(); + int taskAffiliation = INVALID_TASK_ID; + int taskAffiliationColor = 0; + int prevTaskId = INVALID_TASK_ID; + int nextTaskId = INVALID_TASK_ID; + int callingUid = -1; + String callingPackage = ""; + int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; + boolean supportsPictureInPicture = false; + Rect bounds = null; + int minWidth = INVALID_MIN_SIZE; + int minHeight = INVALID_MIN_SIZE; + int persistTaskVersion = 0; + + for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { + final String attrName = in.getAttributeName(attrNdx); + final String attrValue = in.getAttributeValue(attrNdx); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + + attrName + " value=" + attrValue); + switch (attrName) { + case ATTR_TASKID: + if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); + break; + case ATTR_REALACTIVITY: + realActivity = ComponentName.unflattenFromString(attrValue); + break; + case ATTR_REALACTIVITY_SUSPENDED: + realActivitySuspended = Boolean.valueOf(attrValue); + break; + case ATTR_ORIGACTIVITY: + origActivity = ComponentName.unflattenFromString(attrValue); + break; + case ATTR_AFFINITY: + affinity = attrValue; + break; + case ATTR_ROOT_AFFINITY: + rootAffinity = attrValue; + hasRootAffinity = true; + break; + case ATTR_ROOTHASRESET: + rootHasReset = Boolean.parseBoolean(attrValue); + break; + case ATTR_AUTOREMOVERECENTS: + autoRemoveRecents = Boolean.parseBoolean(attrValue); + break; + case ATTR_ASKEDCOMPATMODE: + askedCompatMode = Boolean.parseBoolean(attrValue); + break; + case ATTR_USERID: + userId = Integer.parseInt(attrValue); + break; + case ATTR_USER_SETUP_COMPLETE: + userSetupComplete = Boolean.parseBoolean(attrValue); + break; + case ATTR_EFFECTIVE_UID: + effectiveUid = Integer.parseInt(attrValue); + break; + case ATTR_TASKTYPE: + taskType = Integer.parseInt(attrValue); + break; + case ATTR_LASTDESCRIPTION: + lastDescription = attrValue; + break; + case ATTR_LASTTIMEMOVED: + lastTimeOnTop = Long.parseLong(attrValue); + break; + case ATTR_NEVERRELINQUISH: + neverRelinquishIdentity = Boolean.parseBoolean(attrValue); + break; + case ATTR_TASK_AFFILIATION: + taskAffiliation = Integer.parseInt(attrValue); + break; + case ATTR_PREV_AFFILIATION: + prevTaskId = Integer.parseInt(attrValue); + break; + case ATTR_NEXT_AFFILIATION: + nextTaskId = Integer.parseInt(attrValue); + break; + case ATTR_TASK_AFFILIATION_COLOR: + taskAffiliationColor = Integer.parseInt(attrValue); + break; + case ATTR_CALLING_UID: + callingUid = Integer.parseInt(attrValue); + break; + case ATTR_CALLING_PACKAGE: + callingPackage = attrValue; + break; + case ATTR_RESIZE_MODE: + resizeMode = Integer.parseInt(attrValue); + break; + case ATTR_SUPPORTS_PICTURE_IN_PICTURE: + supportsPictureInPicture = Boolean.parseBoolean(attrValue); + break; + case ATTR_NON_FULLSCREEN_BOUNDS: + bounds = Rect.unflattenFromString(attrValue); + break; + case ATTR_MIN_WIDTH: + minWidth = Integer.parseInt(attrValue); + break; + case ATTR_MIN_HEIGHT: + minHeight = Integer.parseInt(attrValue); + break; + case ATTR_PERSIST_TASK_VERSION: + persistTaskVersion = Integer.parseInt(attrValue); + break; + default: + if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { + taskDescription.restoreFromXml(attrName, attrValue); + } else { + Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); + } + } + } + + int event; + while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && + (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { + if (event == XmlPullParser.START_TAG) { + final String name = in.getName(); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, + "TaskRecord: START_TAG name=" + name); + if (TAG_AFFINITYINTENT.equals(name)) { + affinityIntent = Intent.restoreFromXml(in); + } else if (TAG_INTENT.equals(name)) { + intent = Intent.restoreFromXml(in); + } else if (TAG_ACTIVITY.equals(name)) { + ActivityRecord activity = + ActivityRecord.restoreFromXml(in, stackSupervisor); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + + activity); + if (activity != null) { + activities.add(activity); + } + } else { + Slog.e(TAG, "restoreTask: Unexpected name=" + name); + XmlUtils.skipCurrentTag(in); + } + } + } + if (!hasRootAffinity) { + rootAffinity = affinity; + } else if ("@".equals(rootAffinity)) { + rootAffinity = null; + } + if (effectiveUid <= 0) { + Intent checkIntent = intent != null ? intent : affinityIntent; + effectiveUid = 0; + if (checkIntent != null) { + IPackageManager pm = AppGlobals.getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo( + checkIntent.getComponent().getPackageName(), + PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_DISABLED_COMPONENTS, userId); + if (ai != null) { + effectiveUid = ai.uid; + } + } catch (RemoteException e) { + } + } + Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent + + ": effectiveUid=" + effectiveUid); + } + + if (persistTaskVersion < 1) { + // We need to convert the resize mode of home activities saved before version one if + // they are marked as RESIZE_MODE_RESIZEABLE to + // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation + // before version 1 and the system didn't resize home activities before then. + if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { + resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + } + } else { + // This activity has previously marked itself explicitly as both resizeable and + // supporting picture-in-picture. Since there is no longer a requirement for + // picture-in-picture activities to be resizeable, we can mark this simply as + // resizeable and supporting picture-in-picture separately. + if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { + resizeMode = RESIZE_MODE_RESIZEABLE; + supportsPictureInPicture = true; + } + } + + final TaskRecord task = create(stackSupervisor.mService, taskId, intent, affinityIntent, + affinity, rootAffinity, realActivity, origActivity, rootHasReset, + autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, + activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, + taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, + callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, + userSetupComplete, minWidth, minHeight); + task.updateOverrideConfiguration(bounds); + + for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { + activities.get(activityNdx).setTask(task); + } + + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); + return task; + } + } } diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java index 2c6fe9484662..61b6fa073be9 100644 --- a/services/core/java/com/android/server/display/BrightnessTracker.java +++ b/services/core/java/com/android/server/display/BrightnessTracker.java @@ -196,9 +196,10 @@ public class BrightnessTracker { /** * @param userId userId to fetch data for. + * @param includePackage if false we will null out BrightnessChangeEvent.packageName * @return List of recent {@link BrightnessChangeEvent}s */ - public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId) { + public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId, boolean includePackage) { // TODO include apps from any managed profiles in the brightness information. BrightnessChangeEvent[] events; synchronized (mEventsLock) { @@ -207,7 +208,13 @@ public class BrightnessTracker { ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length); for (int i = 0; i < events.length; ++i) { if (events[i].userId == userId) { - out.add(events[i]); + if (includePackage) { + out.add(events[i]); + } else { + BrightnessChangeEvent event = new BrightnessChangeEvent((events[i])); + event.packageName = null; + out.add(event); + } } } return new ParceledListSlice<>(out); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 379aaadca9ee..19a74d7cdeac 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -29,6 +29,7 @@ import com.android.internal.util.IndentingPrintWriter; import android.Manifest; import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -1752,14 +1753,30 @@ public final class DisplayManagerService extends SystemService { } @Override // Binder call - public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents() { + public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { mContext.enforceCallingOrSelfPermission( Manifest.permission.BRIGHTNESS_SLIDER_USAGE, "Permission to read brightness events."); - int userId = UserHandle.getUserId(Binder.getCallingUid()); + + final int callingUid = Binder.getCallingUid(); + AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); + final int mode = appOpsManager.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + callingUid, callingPackage); + final boolean hasUsageStats; + if (mode == AppOpsManager.MODE_DEFAULT) { + // The default behavior here is to check if PackageManager has given the app + // permission. + hasUsageStats = mContext.checkCallingPermission( + Manifest.permission.PACKAGE_USAGE_STATS) + == PackageManager.PERMISSION_GRANTED; + } else { + hasUsageStats = mode == AppOpsManager.MODE_ALLOWED; + } + + final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { - return mBrightnessTracker.getEvents(userId); + return mBrightnessTracker.getEvents(userId, hasUsageStats); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 019c7c2fe915..7d64aed4fac3 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -39,8 +39,10 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Build; +import android.os.Handler; import android.os.IBinder; import android.os.IInterface; +import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -86,6 +88,7 @@ abstract public class ManagedServices { protected final String TAG = getClass().getSimpleName(); protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000; protected static final String ENABLED_SERVICES_SEPARATOR = ":"; /** @@ -105,12 +108,15 @@ abstract public class ManagedServices { private final IPackageManager mPm; private final UserManager mUm; private final Config mConfig; + private final Handler mHandler = new Handler(Looper.getMainLooper()); // contains connections to all connected services, including app services // and system services private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>(); // things that will be put into mServices as soon as they're ready private final ArrayList<String> mServicesBinding = new ArrayList<>(); + private final ArraySet<String> mServicesRebinding = new ArraySet<>(); + // lists the component names of all enabled (and therefore potentially connected) // app services for current profiles. private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles @@ -890,6 +896,7 @@ abstract public class ManagedServices { final String servicesBindingTag = name.toString() + "/" + userid; if (mServicesBinding.contains(servicesBindingTag)) { + Slog.v(TAG, "Not registering " + name + " as bind is already in progress"); // stop registering this thing already! we're working on it return; } @@ -938,6 +945,7 @@ abstract public class ManagedServices { boolean added = false; ManagedServiceInfo info = null; synchronized (mMutex) { + mServicesRebinding.remove(servicesBindingTag); mServicesBinding.remove(servicesBindingTag); try { mService = asInterface(binder); @@ -959,6 +967,27 @@ abstract public class ManagedServices { mServicesBinding.remove(servicesBindingTag); Slog.v(TAG, getCaption() + " connection lost: " + name); } + + @Override + public void onBindingDied(ComponentName name) { + Slog.w(TAG, getCaption() + " binding died: " + name); + synchronized (mMutex) { + mServicesBinding.remove(servicesBindingTag); + mContext.unbindService(this); + if (!mServicesRebinding.contains(servicesBindingTag)) { + mServicesRebinding.add(servicesBindingTag); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + registerService(name, userid); + } + }, ON_BINDING_DIED_REBIND_DELAY_MS); + } else { + Slog.v(TAG, getCaption() + " not rebinding as " + + "a previous rebind attempt was made: " + name); + } + } + } }; if (!mContext.bindServiceAsUser(intent, serviceConnection, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index bec6fc2c32f7..cf0140072721 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4743,8 +4743,7 @@ public class NotificationManagerService extends SystemService { } void sendAccessibilityEvent(Notification notification, CharSequence packageName) { - if (!mAccessibilityManager.isObservedEventType( - AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)) { + if (!mAccessibilityManager.isEnabled()) { return; } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 1e9fab5ce574..700ccad8527a 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -98,11 +98,6 @@ public class ZenModeHelper { private final Metrics mMetrics = new Metrics(); private final ConditionProviders.Config mServiceConfig; - protected final ArrayList<String> mDefaultRuleIds = new ArrayList<>(); - private final String EVENTS_DEFAULT_RULE = "EVENTS_DEFAULT_RULE"; - private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1"; - private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2"; - @VisibleForTesting protected int mZenMode; private int mUser = UserHandle.USER_SYSTEM; @VisibleForTesting protected ZenModeConfig mConfig; @@ -115,9 +110,8 @@ public class ZenModeHelper { public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS | SUPPRESSED_EFFECT_NOTIFICATIONS; - protected String mDefaultRuleWeeknightsName; + protected String mDefaultRuleEveryNightName; protected String mDefaultRuleEventsName; - protected String mDefaultRuleWeekendsName; public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { mContext = context; @@ -230,12 +224,25 @@ public class ZenModeHelper { config = mDefaultConfig.copy(); config.user = user; } + enforceDefaultRulesExist(config); synchronized (mConfig) { setConfigLocked(config, reason); } cleanUpZenRules(); } + private void enforceDefaultRulesExist(ZenModeConfig config) { + for (String id : ZenModeConfig.DEFAULT_RULE_IDS) { + if (!config.automaticRules.containsKey(id)) { + if (id.equals(ZenModeConfig.EVENTS_DEFAULT_RULE_ID)) { + appendDefaultEventRules(config); + } else if (id.equals(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID)) { + appendDefaultEveryNightRule(config); + } + } + } + } + public int getZenModeListenerInterruptionFilter() { return NotificationManager.zenModeToInterruptionFilter(mZenMode); } @@ -421,17 +428,12 @@ public class ZenModeHelper { public void setDefaultZenRules(Context context) { mDefaultConfig = readDefaultConfig(context.getResources()); - - mDefaultRuleIds.add(EVENTS_DEFAULT_RULE); - mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_1); - mDefaultRuleIds.add(SCHEDULED_DEFAULT_RULE_2); - appendDefaultRules(mDefaultConfig); } private void appendDefaultRules (ZenModeConfig config) { getDefaultRuleNames(); - appendDefaultScheduleRules(config); + appendDefaultEveryNightRule(config); appendDefaultEventRules(config); } @@ -450,7 +452,7 @@ public class ZenModeHelper { protected void updateDefaultZenRules() { ZenModeConfig configDefaultRules = new ZenModeConfig(); appendDefaultRules(configDefaultRules); // "new" localized default rules - for (String ruleId : mDefaultRuleIds) { + for (String ruleId : ZenModeConfig.DEFAULT_RULE_IDS) { AutomaticZenRule currRule = getAutomaticZenRule(ruleId); ZenRule defaultRule = configDefaultRules.automaticRules.get(ruleId); // if default rule wasn't customized, use localized name instead of previous @@ -812,10 +814,8 @@ public class ZenModeHelper { private void getDefaultRuleNames() { // on locale-change, these values differ - mDefaultRuleWeeknightsName = mContext.getResources() - .getString(R.string.zen_mode_default_weeknights_name); - mDefaultRuleWeekendsName = mContext.getResources() - .getString(R.string.zen_mode_default_weekends_name); + mDefaultRuleEveryNightName = mContext.getResources() + .getString(R.string.zen_mode_default_every_night_name); mDefaultRuleEventsName = mContext.getResources() .getString(R.string.zen_mode_default_events_name); } @@ -935,39 +935,23 @@ public class ZenModeHelper { return new ZenModeConfig(); } - private void appendDefaultScheduleRules(ZenModeConfig config) { + private void appendDefaultEveryNightRule(ZenModeConfig config) { if (config == null) return; final ScheduleInfo weeknights = new ScheduleInfo(); - weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS; + weeknights.days = ZenModeConfig.ALL_DAYS; weeknights.startHour = 22; weeknights.endHour = 7; weeknights.exitAtAlarm = true; - final ZenRule rule1 = new ZenRule(); - rule1.enabled = false; - rule1.name = mDefaultRuleWeeknightsName; - rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); - rule1.zenMode = Global.ZEN_MODE_ALARMS; - rule1.component = ScheduleConditionProvider.COMPONENT; - rule1.id = SCHEDULED_DEFAULT_RULE_1; - rule1.creationTime = System.currentTimeMillis(); - config.automaticRules.put(rule1.id, rule1); - - final ScheduleInfo weekends = new ScheduleInfo(); - weekends.days = ZenModeConfig.WEEKEND_DAYS; - weekends.startHour = 23; - weekends.startMinute = 30; - weekends.endHour = 10; - weekends.exitAtAlarm = true; - final ZenRule rule2 = new ZenRule(); - rule2.enabled = false; - rule2.name = mDefaultRuleWeekendsName; - rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends); - rule2.zenMode = Global.ZEN_MODE_ALARMS; - rule2.component = ScheduleConditionProvider.COMPONENT; - rule2.id = SCHEDULED_DEFAULT_RULE_2; - rule2.creationTime = System.currentTimeMillis(); - config.automaticRules.put(rule2.id, rule2); + final ZenRule rule = new ZenRule(); + rule.enabled = false; + rule.name = mDefaultRuleEveryNightName; + rule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); + rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + rule.component = ScheduleConditionProvider.COMPONENT; + rule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID; + rule.creationTime = System.currentTimeMillis(); + config.automaticRules.put(rule.id, rule); } private void appendDefaultEventRules(ZenModeConfig config) { @@ -980,9 +964,9 @@ public class ZenModeHelper { rule.enabled = false; rule.name = mDefaultRuleEventsName; rule.conditionId = ZenModeConfig.toEventConditionId(events); - rule.zenMode = Global.ZEN_MODE_ALARMS; + rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; rule.component = EventConditionProvider.COMPONENT; - rule.id = EVENTS_DEFAULT_RULE; + rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID; rule.creationTime = System.currentTimeMillis(); config.automaticRules.put(rule.id, rule); } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 6a06be2fcaa9..be66fe22ca1b 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -496,6 +496,26 @@ public class Installer extends SystemService { } } + public boolean createProfileSnapshot(int appId, String packageName, String codePath) + throws InstallerException { + if (!checkBeforeRemote()) return false; + try { + return mInstalld.createProfileSnapshot(appId, packageName, codePath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + + public void destroyProfileSnapshot(String packageName, String codePath) + throws InstallerException { + if (!checkBeforeRemote()) return; + try { + mInstalld.destroyProfileSnapshot(packageName, codePath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + public void invalidateMounts() throws InstallerException { if (!checkBeforeRemote()) return; try { diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java index 88fc65e3f7d1..30072d45ccab 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolver.java +++ b/services/core/java/com/android/server/pm/InstantAppResolver.java @@ -40,14 +40,11 @@ import android.content.pm.InstantAppIntentFilter; import android.content.pm.InstantAppResolveInfo; import android.content.pm.InstantAppResolveInfo.InstantAppDigest; import android.metrics.LogMaker; -import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.util.Log; -import android.util.Pair; -import android.util.Slog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -56,11 +53,9 @@ import com.android.server.pm.EphemeralResolverConnection.PhaseTwoCallback; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; -import java.util.concurrent.TimeoutException; /** @hide */ public abstract class InstantAppResolver { @@ -161,6 +156,7 @@ public abstract class InstantAppResolver { final String splitName; final long versionCode; final Intent failureIntent; + final Bundle extras; if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) { final AuxiliaryResolveInfo instantAppIntentInfo = InstantAppResolver.filterInstantAppIntent( @@ -172,17 +168,20 @@ public abstract class InstantAppResolver { splitName = instantAppIntentInfo.splitName; versionCode = instantAppIntentInfo.resolveInfo.getVersionCode(); failureIntent = instantAppIntentInfo.failureIntent; + extras = instantAppIntentInfo.resolveInfo.getExtras(); } else { packageName = null; splitName = null; versionCode = -1; failureIntent = null; + extras = null; } } else { packageName = null; splitName = null; versionCode = -1; failureIntent = null; + extras = null; } final Intent installerIntent = buildEphemeralInstallerIntent( Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE, @@ -197,6 +196,7 @@ public abstract class InstantAppResolver { requestObj.responseObj.installFailureActivity, versionCode, token, + extras, false /*needsPhaseTwo*/); installerIntent.setComponent(new ComponentName( instantAppInstaller.packageName, instantAppInstaller.name)); @@ -243,6 +243,7 @@ public abstract class InstantAppResolver { @Nullable ComponentName installFailureActivity, long versionCode, @Nullable String token, + @Nullable Bundle extras, boolean needsPhaseTwo) { // Construct the intent that launches the instant installer int flags = origIntent.getFlags(); @@ -259,6 +260,9 @@ public abstract class InstantAppResolver { intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost()); } intent.putExtra(Intent.EXTRA_INSTANT_APP_ACTION, origIntent.getAction()); + if (extras != null) { + intent.putExtra(Intent.EXTRA_INSTANT_APP_EXTRAS, extras); + } // We have all of the data we need; just start the installer without a second phase if (!needsPhaseTwo) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9804283837d2..8b2854c56977 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3038,7 +3038,7 @@ public class PackageManagerService extends IPackageManager.Stub } mInstallerService = new PackageInstallerService(context, this); - mArtManagerService = new ArtManagerService(this); + mArtManagerService = new ArtManagerService(this, mInstaller, mInstallLock); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -9495,7 +9495,7 @@ public class PackageManagerService extends IPackageManager.Stub if (expectedCertDigests.length != libCertDigests.length) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + - " static sDexLoadReporter.java:45.19hared library; failing!"); + " static shared library; failing!"); } // Use a predictable order as signature order may vary diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 5a1f840e945b..2dbb34d888e5 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -21,15 +21,23 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.dex.ArtManager; import android.os.Binder; +import android.os.Environment; import android.os.Handler; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.content.pm.IPackageManager; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; +import com.android.server.pm.Installer; +import com.android.server.pm.Installer.InstallerException; +import java.io.File; +import java.io.FileNotFoundException; /** * A system service that provides access to runtime and compiler artifacts. @@ -50,10 +58,16 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { private static boolean DEBUG_IGNORE_PERMISSIONS = false; private final IPackageManager mPackageManager; + private final Object mInstallLock; + @GuardedBy("mInstallLock") + private final Installer mInstaller; + private final Handler mHandler; - public ArtManagerService(IPackageManager pm) { + public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) { mPackageManager = pm; + mInstaller = installer; + mInstallLock = installLock; mHandler = new Handler(BackgroundThread.getHandler().getLooper()); } @@ -105,8 +119,53 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { return; } - // All good, move forward and get the profile. - postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + // All good, create the profile snapshot. + createProfileSnapshot(packageName, codePath, callback, info); + // Destroy the snapshot, we no longer need it. + destroyProfileSnapshot(packageName, codePath); + } + + private void createProfileSnapshot(String packageName, String codePath, + ISnapshotRuntimeProfileCallback callback, PackageInfo info) { + // Ask the installer to snapshot the profile. + synchronized (mInstallLock) { + try { + if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid), + packageName, codePath)) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } catch (InstallerException e) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } + + // Open the snapshot and invoke the callback. + File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath); + ParcelFileDescriptor fd; + try { + fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY); + postSuccess(packageName, fd, callback); + } catch (FileNotFoundException e) { + Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + codePath, e); + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + } + } + + private void destroyProfileSnapshot(String packageName, String codePath) { + if (DEBUG) { + Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath); + } + + synchronized (mInstallLock) { + try { + mInstaller.destroyProfileSnapshot(packageName, codePath); + } catch (InstallerException e) { + Slog.e(TAG, "Failed to destroy profile snapshot for " + + packageName + ":" + codePath, e); + } + } } @Override @@ -123,6 +182,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { */ private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, int errCode) { + if (DEBUG) { + Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " + + errCode); + } mHandler.post(() -> { try { callback.onError(errCode); @@ -132,6 +195,21 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { }); } + private void postSuccess(String packageName, ParcelFileDescriptor fd, + ISnapshotRuntimeProfileCallback callback) { + if (DEBUG) { + Slog.d(TAG, "Successfully snapshot profile for " + packageName); + } + mHandler.post(() -> { + try { + callback.onSuccess(fd); + } catch (RemoteException e) { + Slog.w(TAG, + "Failed to call onSuccess after profile snapshot for " + packageName, e); + } + }); + } + /** * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. * If not, it throws a {@link SecurityException}. diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 7415ec3881b1..4da74521dd20 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -239,6 +239,7 @@ import android.view.autofill.AutofillManagerInternal; import android.view.inputmethod.InputMethodManagerInternal; import com.android.internal.R; +import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -246,6 +247,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.internal.policy.PhoneWindow; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.ScreenShapeHelper; import com.android.internal.widget.PointerLocationView; import com.android.server.GestureLauncherService; @@ -3379,7 +3381,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } boolean keyguardOn() { - return isKeyguardShowingAndNotOccluded() || inKeyguardRestrictedKeyInputMode(); + return isKeyguardShowingAndNotOccluded(); } private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { @@ -6870,13 +6872,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mKeyguardOccluded; } - /** {@inheritDoc} */ - @Override - public boolean inKeyguardRestrictedKeyInputMode() { - if (mKeyguardDelegate == null) return false; - return mKeyguardDelegate.isInputRestricted(); - } - @Override public void dismissKeyguardLw(IKeyguardDismissCallback callback) { if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { @@ -7213,15 +7208,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } static long[] getLongIntArray(Resources r, int resid) { - int[] ar = r.getIntArray(resid); - if (ar == null) { - return null; - } - long[] out = new long[ar.length]; - for (int i=0; i<ar.length; i++) { - out[i] = ar[i]; - } - return out; + return ArrayUtils.convertToLongArray(r.getIntArray(resid)); } private void bindKeyguard() { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 5f067d496e9a..3d458c7ce918 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1357,17 +1357,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public boolean isKeyguardTrustedLw(); /** - * inKeyguardRestrictedKeyInputMode - * - * if keyguard screen is showing or in restricted key input mode (i.e. in - * keyguard password emergency screen). When in such mode, certain keys, - * such as the Home key and the right soft keys, don't work. - * - * @return true if in keyguard restricted input mode. - */ - public boolean inKeyguardRestrictedKeyInputMode(); - - /** * Ask the policy to dismiss the keyguard, if it is currently shown. * * @param callback Callback to be informed about the result. diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 8a40b4dd49fb..6f005a35a28c 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -339,7 +339,7 @@ public class BatterySaverPolicy extends ContentObserver { } mVibrationDisabled = parser.getBoolean(KEY_VIBRATION_DISABLED, true); - mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, true); + mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, false); mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true); mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true); mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true); diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java new file mode 100644 index 000000000000..047e270f3fac --- /dev/null +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.slice; + +import android.app.slice.ISliceManager; +import android.content.Context; + +import com.android.server.SystemService; + +public class SliceManagerService extends ISliceManager.Stub { + + public SliceManagerService(Context context) { + + } + + private void systemReady() { + } + + private void onUnlockUser(int userHandle) { + } + + public static class Lifecycle extends SystemService { + private SliceManagerService mService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new SliceManagerService(getContext()); + publishBinderService(Context.SLICE_SERVICE, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + mService.systemReady(); + } + } + + @Override + public void onUnlockUser(int userHandle) { + mService.onUnlockUser(userHandle); + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 82f842c0fd85..8d8c26c0b1c1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -65,6 +65,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; + +import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN; import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -229,6 +231,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.LatencyTracker; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; @@ -771,6 +774,8 @@ public class WindowManagerService extends IWindowManager.Stub private WindowContentFrameStats mTempWindowRenderStats; + private final LatencyTracker mLatencyTracker; + /** * Whether the UI is currently running in touch mode (not showing * navigational focus because the user is directly pressing the screen). @@ -1070,6 +1075,8 @@ public class WindowManagerService extends IWindowManager.Stub filter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mBroadcastReceiver, filter); + mLatencyTracker = LatencyTracker.getInstance(context); + mSettingsObserver = new SettingsObserver(); mHoldingScreenWakeLock = mPowerManager.newWakeLock( @@ -3046,11 +3053,6 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean inKeyguardRestrictedInputMode() { - return mPolicy.inKeyguardRestrictedKeyInputMode(); - } - - @Override public boolean isKeyguardLocked() { return mPolicy.isKeyguardLocked(); } @@ -5863,6 +5865,7 @@ public class WindowManagerService extends IWindowManager.Stub Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); } + mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN); // TODO(multidisplay): rotation on non-default displays if (CUSTOM_SCREEN_ROTATION && displayContent.isDefaultDisplay) { mExitAnimId = exitAnim; @@ -5987,6 +5990,7 @@ public class WindowManagerService extends IWindowManager.Stub if (configChanged) { mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); } + mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN); } static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps, diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp new file mode 100644 index 000000000000..5d76304627c6 --- /dev/null +++ b/services/core/jni/Android.bp @@ -0,0 +1,121 @@ +cc_library_static { + name: "libservices.core", + defaults: ["libservices.core-libs"], + + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + + "-DEGL_EGLEXT_PROTOTYPES", + "-DGL_GLEXT_PROTOTYPES", + ], + + srcs: [ + "BroadcastRadio/JavaRef.cpp", + "BroadcastRadio/NativeCallbackThread.cpp", + "BroadcastRadio/BroadcastRadioService.cpp", + "BroadcastRadio/Tuner.cpp", + "BroadcastRadio/TunerCallback.cpp", + "BroadcastRadio/convert.cpp", + "BroadcastRadio/regions.cpp", + "com_android_server_AlarmManagerService.cpp", + "com_android_server_am_BatteryStatsService.cpp", + "com_android_server_connectivity_Vpn.cpp", + "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", + "com_android_server_ConsumerIrService.cpp", + "com_android_server_HardwarePropertiesManagerService.cpp", + "com_android_server_hdmi_HdmiCecController.cpp", + "com_android_server_input_InputApplicationHandle.cpp", + "com_android_server_input_InputManagerService.cpp", + "com_android_server_input_InputWindowHandle.cpp", + "com_android_server_lights_LightsService.cpp", + "com_android_server_location_GnssLocationProvider.cpp", + "com_android_server_locksettings_SyntheticPasswordManager.cpp", + "com_android_server_power_PowerManagerService.cpp", + "com_android_server_SerialService.cpp", + "com_android_server_storage_AppFuseBridge.cpp", + "com_android_server_SystemServer.cpp", + "com_android_server_tv_TvUinputBridge.cpp", + "com_android_server_tv_TvInputHal.cpp", + "com_android_server_vr_VrManagerService.cpp", + "com_android_server_UsbDeviceManager.cpp", + "com_android_server_UsbDescriptorParser.cpp", + "com_android_server_UsbMidiDevice.cpp", + "com_android_server_UsbHostManager.cpp", + "com_android_server_VibratorService.cpp", + "com_android_server_PersistentDataBlockService.cpp", + "com_android_server_GraphicsStatsService.cpp", + "onload.cpp", + ], + + include_dirs: [ + "frameworks/base/libs", + "frameworks/native/services", + "system/gatekeeper/include", + ], +} + +cc_defaults { + name: "libservices.core-libs", + shared_libs: [ + "libandroid_runtime", + "libandroidfw", + "libaudioclient", + "libbase", + "libappfuse", + "libbinder", + "libcutils", + "libcrypto", + "liblog", + "libhardware", + "libhardware_legacy", + "libhidlbase", + "libkeystore_binder", + "libnativehelper", + "libutils", + "libui", + "libinput", + "libinputflinger", + "libinputservice", + "libschedulerservicehidl", + "libsensorservice", + "libsensorservicehidl", + "libgui", + "libusbhost", + "libsuspend", + "libEGL", + "libGLESv2", + "libnetutils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "libhwui", + "android.hardware.audio.common@2.0", + "android.hardware.broadcastradio@1.0", + "android.hardware.broadcastradio@1.1", + "android.hardware.broadcastradio@1.2", + "android.hardware.contexthub@1.0", + "android.hardware.gnss@1.0", + "android.hardware.gnss@1.1", + "android.hardware.ir@1.0", + "android.hardware.light@2.0", + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.tetheroffload.config@1.0", + "android.hardware.thermal@1.0", + "android.hardware.tv.cec@1.0", + "android.hardware.tv.input@1.0", + "android.hardware.vibrator@1.0", + "android.hardware.vibrator@1.1", + "android.hardware.vr@1.0", + "android.frameworks.schedulerservice@1.0", + "android.frameworks.sensorservice@1.0", + ], + + static_libs: [ + "android.hardware.broadcastradio@common-utils-lib", + "libscrypt_static", + ], +} diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk deleted file mode 100644 index 8b9cf4beec9b..000000000000 --- a/services/core/jni/Android.mk +++ /dev/null @@ -1,114 +0,0 @@ -# This file is included by the top level services directory to collect source -# files -LOCAL_REL_DIR := core/jni - -LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter - -LOCAL_SRC_FILES += \ - $(LOCAL_REL_DIR)/BroadcastRadio/JavaRef.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/NativeCallbackThread.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/BroadcastRadioService.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \ - $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \ - $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ - $(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \ - $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \ - $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ - $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \ - $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \ - $(LOCAL_REL_DIR)/com_android_server_locksettings_SyntheticPasswordManager.cpp \ - $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \ - $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \ - $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \ - $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \ - $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \ - $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \ - $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \ - $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \ - $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_GraphicsStatsService.cpp \ - $(LOCAL_REL_DIR)/onload.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/scrypt/lib/crypto \ - frameworks/base/services \ - frameworks/base/libs \ - frameworks/base/core/jni \ - frameworks/native/services \ - system/core/libappfuse/include \ - system/gatekeeper/include \ - system/security/keystore/include \ - $(call include-path-for, libhardware)/hardware \ - $(call include-path-for, libhardware_legacy)/hardware_legacy \ - -LOCAL_SHARED_LIBRARIES += \ - libandroid_runtime \ - libandroidfw \ - libaudioclient \ - libbase \ - libappfuse \ - libbinder \ - libcutils \ - libcrypto \ - liblog \ - libhardware \ - libhardware_legacy \ - libhidlbase \ - libkeystore_binder \ - libnativehelper \ - libutils \ - libui \ - libinput \ - libinputflinger \ - libinputservice \ - libschedulerservicehidl \ - libsensorservice \ - libsensorservicehidl \ - libgui \ - libusbhost \ - libsuspend \ - libEGL \ - libGLESv2 \ - libnetutils \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - libutils \ - libhwui \ - android.hardware.audio.common@2.0 \ - android.hardware.broadcastradio@1.0 \ - android.hardware.broadcastradio@1.1 \ - android.hardware.broadcastradio@1.2 \ - android.hardware.contexthub@1.0 \ - android.hardware.gnss@1.0 \ - android.hardware.gnss@1.1 \ - android.hardware.ir@1.0 \ - android.hardware.light@2.0 \ - android.hardware.power@1.0 \ - android.hardware.power@1.1 \ - android.hardware.tetheroffload.config@1.0 \ - android.hardware.thermal@1.0 \ - android.hardware.tv.cec@1.0 \ - android.hardware.tv.input@1.0 \ - android.hardware.vibrator@1.0 \ - android.hardware.vibrator@1.1 \ - android.hardware.vr@1.0 \ - android.frameworks.schedulerservice@1.0 \ - android.frameworks.sensorservice@1.0 \ - -LOCAL_STATIC_LIBRARIES += \ - android.hardware.broadcastradio@common-utils-lib \ - libscrypt_static \ diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp index 232b2c2c8c86..514b6e1c2f70 100644 --- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp +++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp @@ -65,11 +65,11 @@ bool NativeInputApplicationHandle::updateInfo() { gInputApplicationHandleClassInfo.name)); if (nameObj) { const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - mInfo->name.setTo(nameStr); + mInfo->name = nameStr; env->ReleaseStringUTFChars(nameObj, nameStr); env->DeleteLocalRef(nameObj); } else { - mInfo->name.setTo("<null>"); + mInfo->name = "<null>"; } mInfo->dispatchingTimeout = env->GetLongField(obj, diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 21300ed37218..27c2faca9d33 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -32,6 +32,7 @@ #include <atomic> #include <cinttypes> #include <limits.h> +#include <android-base/stringprintf.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> @@ -65,6 +66,8 @@ #define INDENT " " +using android::base::StringPrintf; + namespace android { // The exponent used to calculate the pointer speed scaling factor. @@ -198,7 +201,7 @@ public: inline sp<InputManager> getInputManager() const { return mInputManager; } - void dump(String8& dump); + void dump(std::string& dump); void setVirtualDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray); void setDisplayViewport(int32_t viewportType, const DisplayViewport& viewport); @@ -240,7 +243,7 @@ public: virtual void notifyConfigurationChanged(nsecs_t when); virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputWindowHandle>& inputWindowHandle, - const String8& reason); + const std::string& reason); virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags); virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); @@ -347,28 +350,28 @@ NativeInputManager::~NativeInputManager() { env->DeleteGlobalRef(mServiceObj); } -void NativeInputManager::dump(String8& dump) { - dump.append("Input Manager State:\n"); +void NativeInputManager::dump(std::string& dump) { + dump += "Input Manager State:\n"; { - dump.appendFormat(INDENT "Interactive: %s\n", toString(mInteractive.load())); + dump += StringPrintf(INDENT "Interactive: %s\n", toString(mInteractive.load())); } { AutoMutex _l(mLock); - dump.appendFormat(INDENT "System UI Visibility: 0x%0" PRIx32 "\n", + dump += StringPrintf(INDENT "System UI Visibility: 0x%0" PRIx32 "\n", mLocked.systemUiVisibility); - dump.appendFormat(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed); - dump.appendFormat(INDENT "Pointer Gestures Enabled: %s\n", + dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed); + dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n", toString(mLocked.pointerGesturesEnabled)); - dump.appendFormat(INDENT "Show Touches: %s\n", toString(mLocked.showTouches)); - dump.appendFormat(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture)); + dump += StringPrintf(INDENT "Show Touches: %s\n", toString(mLocked.showTouches)); + dump += StringPrintf(INDENT "Pointer Capture Enabled: %s\n", toString(mLocked.pointerCapture)); } - dump.append("\n"); + dump += "\n"; mInputManager->getReader()->dump(dump); - dump.append("\n"); + dump += "\n"; mInputManager->getDispatcher()->dump(dump); - dump.append("\n"); + dump += "\n"; } bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { @@ -668,7 +671,7 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { } nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) { + const sp<InputWindowHandle>& inputWindowHandle, const std::string& reason) { #if DEBUG_INPUT_DISPATCHER_POLICY ALOGD("notifyANR"); #endif @@ -680,7 +683,7 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); - jstring reasonObj = env->NewStringUTF(reason.string()); + jstring reasonObj = env->NewStringUTF(reason.c_str()); jlong newTimeout = env->CallLongMethod(mServiceObj, gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj, @@ -1342,7 +1345,7 @@ static void handleInputChannelDisposed(JNIEnv* env, NativeInputManager* im = static_cast<NativeInputManager*>(data); ALOGW("Input channel object '%s' was disposed without first being unregistered with " - "the input manager!", inputChannel->getName().string()); + "the input manager!", inputChannel->getName().c_str()); im->unregisterInputChannel(env, inputChannel); } @@ -1363,9 +1366,9 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, status_t status = im->registerInputChannel( env, inputChannel, inputWindowHandle, monitor); if (status) { - String8 message; - message.appendFormat("Failed to register input channel. status=%d", status); - jniThrowRuntimeException(env, message.string()); + std::string message; + message += StringPrintf("Failed to register input channel. status=%d", status); + jniThrowRuntimeException(env, message.c_str()); return; } @@ -1390,9 +1393,9 @@ static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */, status_t status = im->unregisterInputChannel(env, inputChannel); if (status && status != BAD_VALUE) { // ignore already unregistered channel - String8 message; - message.appendFormat("Failed to unregister input channel. status=%d", status); - jniThrowRuntimeException(env, message.string()); + std::string message; + message += StringPrintf("Failed to unregister input channel. status=%d", status); + jniThrowRuntimeException(env, message.c_str()); } } @@ -1576,9 +1579,9 @@ static void nativeReloadDeviceAliases(JNIEnv* /* env */, static jstring nativeDump(JNIEnv* env, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - String8 dump; + std::string dump; im->dump(dump); - return env->NewStringUTF(dump.string()); + return env->NewStringUTF(dump.c_str()); } static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp index 2b2a6fac9b6a..c13aa38dc133 100644 --- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp +++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp @@ -103,11 +103,11 @@ bool NativeInputWindowHandle::updateInfo() { gInputWindowHandleClassInfo.name)); if (nameObj) { const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - mInfo->name.setTo(nameStr); + mInfo->name = nameStr; env->ReleaseStringUTFChars(nameObj, nameStr); env->DeleteLocalRef(nameObj); } else { - mInfo->name.setTo("<null>"); + mInfo->name = "<null>"; } mInfo->layoutParamsFlags = env->GetIntField(obj, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ddc0c2339050..b979ff46702d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -19,6 +19,7 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.BIND_DEVICE_ADMIN; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; +import static android.app.ActivityManager.USER_OP_SUCCESS; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; @@ -150,6 +151,9 @@ import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.ParcelableKeyGenParameterSpec; +import android.security.KeyStore; import android.service.persistentdata.PersistentDataBlockManager; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -5021,6 +5025,54 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm, + ParcelableKeyGenParameterSpec parcelableKeySpec) { + enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, + DELEGATION_CERT_INSTALL); + final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec(); + if (TextUtils.isEmpty(keySpec.getKeystoreAlias())) { + throw new IllegalArgumentException("Empty alias provided."); + } + // As the caller will be granted access to the key, ensure no UID was specified, as + // it will not have the desired effect. + if (keySpec.getUid() != KeyStore.UID_SELF) { + Log.e(LOG_TAG, "Only the caller can be granted access to the generated keypair."); + return false; + } + final int callingUid = mInjector.binderGetCallingUid(); + + final UserHandle userHandle = mInjector.binderGetCallingUserHandle(); + final long id = mInjector.binderClearCallingIdentity(); + try { + try (KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, userHandle)) { + IKeyChainService keyChain = keyChainConnection.getService(); + final boolean generationResult = keyChain.generateKeyPair(algorithm, parcelableKeySpec); + if (!generationResult) { + Log.e(LOG_TAG, "KeyChain failed to generate a keypair."); + return false; + } + + // Set a grant for the caller here so that when the client calls + // requestPrivateKey, it will be able to get the key from Keystore. + // Note the use of the calling UID, since the request for the private + // key will come from the client's process, so the grant has to be for + // that UID. + keyChain.setGrant(callingUid, keySpec.getKeystoreAlias(), true); + return true; + } + } catch (RemoteException e) { + Log.e(LOG_TAG, "KeyChain error while generating a keypair", e); + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while generating keypair", e); + Thread.currentThread().interrupt(); + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + return false; + } + + @Override public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) { // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. @@ -8403,6 +8455,90 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public boolean stopUser(ComponentName who, UserHandle userHandle) { + Preconditions.checkNotNull(who, "ComponentName is null"); + + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + } + + final int userId = userHandle.getIdentifier(); + if (isManagedProfile(userId)) { + Log.w(LOG_TAG, "Managed profile cannot be stopped"); + return false; + } + + final long id = mInjector.binderClearCallingIdentity(); + try { + return mInjector.getIActivityManager().stopUser(userId, true /*force*/, null) + == USER_OP_SUCCESS; + } catch (RemoteException e) { + // Same process, should not happen. + return false; + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + } + + @Override + public boolean logoutUser(ComponentName who) { + Preconditions.checkNotNull(who, "ComponentName is null"); + + final int callingUserId = mInjector.userHandleGetCallingUserId(); + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (!isUserAffiliatedWithDeviceLocked(callingUserId)) { + throw new SecurityException("Admin " + who + + " is neither the device owner or affiliated user's profile owner."); + } + } + + if (isManagedProfile(callingUserId)) { + Log.w(LOG_TAG, "Managed profile cannot be logout"); + return false; + } + + final long id = mInjector.binderClearCallingIdentity(); + try { + if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) { + Log.w(LOG_TAG, "Failed to switch to primary user"); + return false; + } + return mInjector.getIActivityManager().stopUser(callingUserId, true /*force*/, null) + == USER_OP_SUCCESS; + } catch (RemoteException e) { + // Same process, should not happen. + return false; + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + } + + @Override + public List<UserHandle> getSecondaryUsers(ComponentName who) { + Preconditions.checkNotNull(who, "ComponentName is null"); + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + } + + final long id = mInjector.binderClearCallingIdentity(); + try { + final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true + /*excludeDying*/); + final List<UserHandle> userHandles = new ArrayList<>(); + for (UserInfo userInfo : userInfos) { + UserHandle userHandle = userInfo.getUserHandle(); + if (!userHandle.isSystem() && !isManagedProfile(userHandle.getIdentifier())) { + userHandles.add(userInfo.getUserHandle()); + } + } + return userHandles; + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + } + + @Override public Bundle getApplicationRestrictions(ComponentName who, String callerPackage, String packageName) { enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 33f4e3487f76..4c994b94e71b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -215,6 +215,9 @@ public final class SystemServer { "com.android.server.timezone.RulesManagerService$Lifecycle"; private static final String IOT_SERVICE_CLASS = "com.google.android.things.services.IoTSystemService"; + private static final String SLICE_MANAGER_SERVICE_CLASS = + "com.android.server.slice.SliceManagerService$Lifecycle"; + private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file"; @@ -730,6 +733,7 @@ public final class SystemServer { boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false); boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice", false); + boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false); boolean enableLeftyService = SystemProperties.getBoolean("config.enable_lefty", false); boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1"); @@ -1523,6 +1527,12 @@ public final class SystemServer { } } + if (!disableSlices) { + traceBeginAndSlog("StartSliceManagerService"); + mSystemServiceManager.startService(SLICE_MANAGER_SERVICE_CLASS); + traceEnd(); + } + if (!disableCameraService) { traceBeginAndSlog("StartCameraServiceProxy"); mSystemServiceManager.startService(CameraServiceProxy.class); diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index e5ab44ffaf6b..218a2b89bbc1 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -38,7 +38,7 @@ LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src) LOCAL_JAVA_LIBRARIES := \ android.hidl.manager-V1.0-java \ android.test.mock \ - legacy-android-test \ + android.test.base android.test.runner \ LOCAL_PACKAGE_NAME := FrameworksServicesTests LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java index 56765101baa9..7160d7fc8c2f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java @@ -19,31 +19,16 @@ package com.android.server.am; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import android.app.ActivityOptions; -import android.app.IApplicationThread; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; -import android.os.IBinder; import android.platform.test.annotations.Presubmit; -import android.service.voice.IVoiceInteractionSession; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import com.android.internal.app.IVoiceInteractor; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.am.ActivityStarter.Factory; import org.junit.runner.RunWith; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyObject; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -73,59 +58,10 @@ public class ActivityStartControllerTests extends ActivityTestsBase { super.setUp(); mService = createActivityManagerService(); mFactory = mock(Factory.class); - mStarter = mock(ActivityStarter.class); - doReturn(mStarter).when(mFactory).getStarter(any(), any(), any(), any()); mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory); - } - - /** - * Ensures that the starter is correctly invoked on - * {@link ActivityStartController#startActivity} - */ - @Test - @Presubmit - public void testStartActivity() { - final Random random = new Random(); - - final IApplicationThread applicationThread = mock(IApplicationThread.class); - final Intent intent = mock(Intent.class); - final Intent ephemeralIntent = mock(Intent.class); - final String resolvedType = "TestType"; - final ActivityInfo aInfo = mock(ActivityInfo.class); - final ResolveInfo rInfo = mock(ResolveInfo.class); - final IVoiceInteractionSession voiceInteractionSession = - mock(IVoiceInteractionSession.class); - final IVoiceInteractor voiceInteractor = mock(IVoiceInteractor.class); - final IBinder resultTo = mock(IBinder.class); - final String resultWho = "resultWho"; - final int requestCode = random.nextInt(); - final int callingPid = random.nextInt(); - final int callingUid = random.nextInt(); - final String callingPackage = "callingPackage"; - final int realCallingPid = random.nextInt(); - final int realCallingUid = random.nextInt(); - final int startFlags = random.nextInt(); - final ActivityOptions options = mock(ActivityOptions.class); - final boolean ignoreTargetSecurity = random.nextBoolean(); - final boolean componentSpecified = random.nextBoolean(); - final ActivityRecord[] outActivity = new ActivityRecord[1]; - final TaskRecord inTask = mock(TaskRecord.class); - final String reason ="reason"; - - mController.startActivity(applicationThread, intent, ephemeralIntent, resolvedType, - aInfo, rInfo, voiceInteractionSession, voiceInteractor, resultTo, resultWho, - requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, - startFlags, options, ignoreTargetSecurity, componentSpecified, outActivity, inTask, - reason); - - // The starter should receive a start command with the originally provided parameters - verify(mStarter, times(1)).startActivityLocked(eq(applicationThread), eq(intent), - eq(ephemeralIntent), eq(resolvedType), eq(aInfo), eq(rInfo), - eq(voiceInteractionSession), eq(voiceInteractor), eq(resultTo), eq(resultWho), - eq(requestCode), eq(callingPid), eq(callingUid), eq(callingPackage), - eq(realCallingPid), eq(realCallingUid), eq(startFlags), eq(options), - eq(ignoreTargetSecurity), eq(componentSpecified), eq(outActivity), eq(inTask), - eq(reason)); + mStarter = spy(new ActivityStarter(mController, mService, mService.mStackSupervisor, + mock(ActivityStartInterceptor.class))); + doReturn(mStarter).when(mFactory).obtainStarter(); } /** @@ -149,7 +85,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { final boolean resume = random.nextBoolean(); mController.doPendingActivityLaunches(resume); - verify(mStarter, times(1)).startActivity(eq(activity), eq(source), eq(null), + verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null), eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null)); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index 471726b2979a..e8194dd8e777 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -166,10 +166,9 @@ public class ActivityStarterTests extends ActivityTestsBase { * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP}) * and the launch flags specified in the intent. The method constructs a call to - * {@link ActivityStarter#startActivityLocked} based on these preconditions and ensures the - * result matches the expected. It is important to note that the method also checks side effects - * of the start, such as ensuring {@link ActivityOptions#abort()} is called in the relevant - * scenarios. + * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches + * the expected. It is important to note that the method also checks side effects of the start, + * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios. * @param preconditions A bitmask representing the preconditions for the launch * @param launchFlags The launch flags to be provided by the launch {@link Intent}. * @param expectedResult The expected result from the launch. @@ -254,14 +253,13 @@ public class ActivityStarterTests extends ActivityTestsBase { final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE) ? 1 : 0; - final int result = starter.startActivityLocked(caller, intent, - null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/, - null /*voiceSession*/, null /*voiceInteractor*/, resultTo, - null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/, - null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/, - 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/, - false /*componentSpecified*/, null /*outActivity*/, - null /*inTask*/, "testLaunchActivityPermissionDenied"); + final int result = starter.setCaller(caller) + .setIntent(intent) + .setActivityInfo(aInfo) + .setResultTo(resultTo) + .setRequestCode(requestCode) + .setReason("testLaunchActivityPermissionDenied") + .execute(); // In some cases the expected result internally is different than the published result. We // must use ActivityStarter#getExternalResult to translate. @@ -269,15 +267,18 @@ public class ActivityStarterTests extends ActivityTestsBase { // Ensure that {@link ActivityOptions} are aborted with unsuccessful result. if (expectedResult != START_SUCCESS) { + final ActivityStarter optionStarter = new ActivityStarter(mController, mService, + mService.mStackSupervisor, mock(ActivityStartInterceptor.class)); final ActivityOptions options = spy(ActivityOptions.makeBasic()); - final int optionResult = starter.startActivityLocked(caller, intent, - null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/, - null /*voiceSession*/, null /*voiceInteractor*/, resultTo, - null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/, - null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/, - 0 /*startFlags*/, options /*options*/, false /*ignoreTargetSecurity*/, - false /*componentSpecified*/, null /*outActivity*/, - null /*inTask*/, "testLaunchActivityPermissionDenied"); + + final int optionResult = optionStarter.setCaller(caller) + .setIntent(intent) + .setActivityInfo(aInfo) + .setResultTo(resultTo) + .setRequestCode(requestCode) + .setReason("testLaunchActivityPermissionDenied") + .setActivityOptions(options) + .execute(); verify(options, times(1)).abort(); } } diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java index 54df744ad41b..d2ae22b43445 100644 --- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java @@ -30,6 +30,7 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; import static android.os.Process.SYSTEM_UID; +import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_LOCKED; import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_PINNED; @@ -53,6 +54,7 @@ import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; +import android.telecom.TelecomManager; import android.util.Pair; import com.android.internal.statusbar.IStatusBarService; @@ -90,6 +92,7 @@ public class LockTaskControllerTest { @Mock private LockPatternUtils mLockPatternUtils; @Mock private LockTaskNotify mLockTaskNotify; @Mock private StatusBarManagerInternal mStatusBarManagerInternal; + @Mock private TelecomManager mTelecomManager; @Mock private RecentTasks mRecentTasks; private LockTaskController mLockTaskController; @@ -118,6 +121,7 @@ public class LockTaskControllerTest { mLockTaskController.setWindowManager(mWindowManager); mLockTaskController.mStatusBarService = mStatusBarService; mLockTaskController.mDevicePolicyManager = mDevicePolicyManager; + mLockTaskController.mTelecomManager = mTelecomManager; mLockTaskController.mLockPatternUtils = mLockPatternUtils; mLockTaskController.mLockTaskNotify = mLockTaskNotify; @@ -209,7 +213,7 @@ public class LockTaskControllerTest { @Test public void testLockTaskViolation() throws Exception { - // GIVEN one task records with whitelisted auth that is in lock task mode + // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -234,6 +238,38 @@ public class LockTaskControllerTest { } @Test + public void testLockTaskViolation_emergencyCall() throws Exception { + // GIVEN one task record with whitelisted auth that is in lock task mode + TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); + mLockTaskController.startLockTaskMode(tr, false, TEST_UID); + + // GIVEN tasks necessary for emergency calling + TaskRecord keypad = getTaskRecord(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT), + TaskRecord.LOCK_TASK_AUTH_PINNABLE); + TaskRecord callAction = getTaskRecord(new Intent(Intent.ACTION_CALL_EMERGENCY), + TaskRecord.LOCK_TASK_AUTH_PINNABLE); + TaskRecord dialer = getTaskRecord("com.example.dialer", TaskRecord.LOCK_TASK_AUTH_PINNABLE); + when(mTelecomManager.getSystemDialerPackage()) + .thenReturn(dialer.intent.getComponent().getPackageName()); + + // GIVEN keyguard is allowed for lock task mode + mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_KEYGUARD); + + // THEN the above tasks should all be allowed + assertFalse(mLockTaskController.isLockTaskModeViolation(keypad)); + assertFalse(mLockTaskController.isLockTaskModeViolation(callAction)); + assertFalse(mLockTaskController.isLockTaskModeViolation(dialer)); + + // GIVEN keyguard is disallowed for lock task mode (default) + mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NONE); + + // THEN the above tasks should all be blocked + assertTrue(mLockTaskController.isLockTaskModeViolation(keypad)); + assertTrue(mLockTaskController.isLockTaskModeViolation(callAction)); + assertTrue(mLockTaskController.isLockTaskModeViolation(dialer)); + } + + @Test public void testStopLockTaskMode() throws Exception { // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); @@ -568,10 +604,15 @@ public class LockTaskControllerTest { } private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) { + final Intent intent = new Intent() + .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME)); + return getTaskRecord(intent, lockTaskAuth); + } + + private TaskRecord getTaskRecord(Intent intent, int lockTaskAuth) { TaskRecord tr = mock(TaskRecord.class); tr.mLockTaskAuth = lockTaskAuth; - tr.intent = new Intent() - .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME)); + tr.intent = intent; tr.userId = TEST_USER_ID; return tr; } diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java new file mode 100644 index 000000000000..5520bd71ad57 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.server.am; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.platform.test.annotations.Presubmit; +import android.service.voice.IVoiceInteractionSession; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.internal.app.IVoiceInteractor; +import com.android.server.am.TaskRecord.TaskRecordFactory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * Tests for exercising {@link TaskRecord}. + * + * Build/Install/Run: + * bit FrameworksServicesTests:com.android.server.am.TaskRecordTests + */ +@MediumTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class TaskRecordTests { + + @Before + public void setUp() throws Exception { + TaskRecord.setTaskRecordFactory(null); + } + + @Test + public void testDefaultTaskFactoryNotNull() throws Exception { + assertNotNull(TaskRecord.getTaskRecordFactory()); + } + + @Test + public void testCreateTestRecordUsingCustomizedFactory() throws Exception { + TestTaskRecordFactory factory = new TestTaskRecordFactory(); + TaskRecord.setTaskRecordFactory(factory); + + assertFalse(factory.mCreated); + + TaskRecord.create(null, 0, null, null, null, null); + + assertTrue(factory.mCreated); + } + + private static class TestTaskRecordFactory extends TaskRecordFactory { + private boolean mCreated = false; + + @Override + TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, + IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) { + mCreated = true; + return null; + } + + @Override + TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, + Intent intent, + ActivityManager.TaskDescription taskDescription) { + mCreated = true; + return null; + } + + @Override + TaskRecord create(ActivityManagerService service, int taskId, Intent intent, + Intent affinityIntent, String affinity, String rootAffinity, + ComponentName realActivity, + ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, + boolean askedCompatMode, int userId, int effectiveUid, String lastDescription, + ArrayList<ActivityRecord> activities, long lastTimeMoved, + boolean neverRelinquishIdentity, + ActivityManager.TaskDescription lastTaskDescription, + int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, + int callingUid, String callingPackage, int resizeMode, + boolean supportsPictureInPicture, + boolean realActivitySuspended, boolean userSetupComplete, int minWidth, + int minHeight) { + mCreated = true; + return null; + } + + @Override + TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) + throws IOException, XmlPullParserException { + mCreated = true; + return null; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java index 6a1d26862715..926009ebfbae 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java @@ -134,7 +134,7 @@ public class BrightnessTrackerTest { mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); mTracker.stop(); assertEquals(1, events.size()); @@ -169,7 +169,9 @@ public class BrightnessTrackerTest { final long sensorTime = mInjector.currentTimeMillis(); mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> eventsNoPackage + = mTracker.getEvents(0, false).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); mTracker.stop(); assertEquals(1, events.size()); @@ -184,6 +186,9 @@ public class BrightnessTrackerTest { assertEquals(3333, event.colorTemperature); assertEquals("a.package", event.packageName); assertEquals(0, event.userId); + + assertEquals(1, eventsNoPackage.size()); + assertNull(eventsNoPackage.get(0).packageName); } @Test @@ -200,7 +205,7 @@ public class BrightnessTrackerTest { (int) mInjector.mSystemIntSettings.get(Settings.System.SCREEN_BRIGHTNESS)); mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); // No events because we filtered out our change. assertEquals(0, events.size()); @@ -217,7 +222,7 @@ public class BrightnessTrackerTest { secondUserUpdateBrightness); mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); - events = mTracker.getEvents(0).getList(); + events = mTracker.getEvents(0, true).getList(); assertEquals(2, events.size()); // First event is change from system update (20) to first user update (20) @@ -242,7 +247,7 @@ public class BrightnessTrackerTest { mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); } - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); mTracker.stop(); // Should be capped at 100 events, and they should be the most recent 100. @@ -266,7 +271,7 @@ public class BrightnessTrackerTest { } mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor( Settings.System.SCREEN_BRIGHTNESS)); - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); mTracker.stop(); assertEquals(1, events.size()); @@ -317,7 +322,7 @@ public class BrightnessTrackerTest { + Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>" + "</events>"; tracker.readEventsLocked(getInputStream(eventFile)); - List<BrightnessChangeEvent> events = tracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList(); assertEquals(1, events.size()); BrightnessChangeEvent event = events.get(0); assertEquals(someTimeAgo, event.timeStamp); @@ -330,7 +335,7 @@ public class BrightnessTrackerTest { assertEquals(1.0f, event.batteryLevel, 0.01); assertEquals("com.example.app", event.packageName); - events = tracker.getEvents(1).getList(); + events = tracker.getEvents(1, true).getList(); assertEquals(1, events.size()); event = events.get(0); assertEquals(someTimeAgo, event.timeStamp); @@ -359,7 +364,7 @@ public class BrightnessTrackerTest { } catch (IOException e) { // Expected; } - assertEquals(0, tracker.getEvents(0).getList().size()); + assertEquals(0, tracker.getEvents(0, true).getList().size()); // Missing lux value. eventFile = @@ -374,7 +379,7 @@ public class BrightnessTrackerTest { } catch (IOException e) { // Expected; } - assertEquals(0, tracker.getEvents(0).getList().size()); + assertEquals(0, tracker.getEvents(0, true).getList().size()); } @Test @@ -405,7 +410,7 @@ public class BrightnessTrackerTest { BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(), mInjector); tracker.readEventsLocked(input); - List<BrightnessChangeEvent> events = tracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList(); assertEquals(1, events.size()); BrightnessChangeEvent event = events.get(0); @@ -442,12 +447,12 @@ public class BrightnessTrackerTest { Settings.System.SCREEN_BRIGHTNESS)); final long eventTime = mInjector.currentTimeMillis(); - List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList(); + List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); assertEquals(2, events.size()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); mTracker.writeEventsLocked(baos); - events = mTracker.getEvents(0).getList(); + events = mTracker.getEvents(0, true).getList(); mTracker.stop(); assertEquals(1, events.size()); diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index c73534196f45..481c898414ac 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -411,11 +411,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public boolean inKeyguardRestrictedKeyInputMode() { - return false; - } - - @Override public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) { } diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk index c7657f65a2b4..0848fd51fa71 100644 --- a/services/tests/shortcutmanagerutils/Android.mk +++ b/services/tests/shortcutmanagerutils/Android.mk @@ -21,7 +21,8 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := \ mockito-target \ - legacy-android-test + legacy-android-test \ + android.test.runner.stubs LOCAL_MODULE_TAGS := optional diff --git a/services/tests/notification/Android.mk b/services/tests/uiservicestests/Android.mk index 597a5849a1a0..40e78785b9f5 100644 --- a/services/tests/notification/Android.mk +++ b/services/tests/uiservicestests/Android.mk @@ -1,5 +1,5 @@ ######################################################################### -# Build FrameworksNotificationTests package +# Build FrameworksUiServicesTests package ######################################################################### LOCAL_PATH:= $(call my-dir) @@ -25,12 +25,12 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ platform-test-annotations \ testables -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_JACK_FLAGS := --multi-dex native LOCAL_DX_FLAGS := --multi-dex -LOCAL_PACKAGE_NAME := FrameworksNotificationTests +LOCAL_PACKAGE_NAME := FrameworksUiServicesTests LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml index c20020abb85c..621b4572c467 100644 --- a/services/tests/notification/AndroidManifest.xml +++ b/services/tests/uiservicestests/AndroidManifest.xml @@ -15,7 +15,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.tests.notification"> + package="com.android.frameworks.tests.uiservices"> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> @@ -32,6 +32,6 @@ <instrumentation android:name="android.testing.TestableInstrumentation" - android:targetPackage="com.android.frameworks.tests.notification" + android:targetPackage="com.android.frameworks.tests.uiservices" android:label="Notification Tests" /> </manifest> diff --git a/services/tests/notification/AndroidTest.xml b/services/tests/uiservicestests/AndroidTest.xml index 448bc3de5a0e..d3b9d4a72ab8 100644 --- a/services/tests/notification/AndroidTest.xml +++ b/services/tests/uiservicestests/AndroidTest.xml @@ -13,16 +13,16 @@ See the License for the specific language governing permissions and limitations under the License. --> -<configuration description="Runs Frameworks Notification Tests."> +<configuration description="Runs Frameworks UI Services Tests."> <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> - <option name="test-file-name" value="FrameworksNotificationTests.apk" /> + <option name="test-file-name" value="FrameworksUiServicesTests.apk" /> </target_preparer> <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="framework-base-presubmit" /> - <option name="test-tag" value="FrameworksNotificationTests" /> + <option name="test-tag" value="FrameworksUiServicesTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > - <option name="package" value="com.android.frameworks.tests.notification" /> + <option name="package" value="com.android.frameworks.tests.uiservices" /> <option name="runner" value="android.testing.TestableInstrumentation" /> </test> </configuration> diff --git a/services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java index faf6a9b76434..faf6a9b76434 100644 --- a/services/tests/notification/src/com/android/server/notification/AlertRateLimiterTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java index 262516dda7ad..262516dda7ad 100644 --- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 0b4d61fb783e..0b4d61fb783e 100644 --- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java index f92bd842e815..f92bd842e815 100644 --- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index f75c648f3c3e..f75c648f3c3e 100644 --- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java index d325e10b5897..d325e10b5897 100644 --- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index a4b9b256aa07..a4b9b256aa07 100644 --- a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java index e52764450ee5..e52764450ee5 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java index d75213c3e773..d75213c3e773 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java index f457f6a550c1..f457f6a550c1 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java index 1e5f96f7be3a..1e5f96f7be3a 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java index 85852f90c281..85852f90c281 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index d767ba2e8487..d767ba2e8487 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 55ec133a29da..55ec133a29da 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index ef26705aa71c..ef26705aa71c 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java index fec28115b418..fec28115b418 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationStatsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java index 4165e9e0aceb..4165e9e0aceb 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTestCase.java index 1ee34122f65a..1ee34122f65a 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTestCase.java diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java index 2d03f111e528..2d03f111e528 100644 --- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java diff --git a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java index e354267dce21..e354267dce21 100644 --- a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java index 4eb42201f072..4eb42201f072 100644 --- a/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java index ba5ad8159029..610592f6b71c 100644 --- a/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleConditionProviderTest.java @@ -1,49 +1,51 @@ package com.android.server.notification; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.spy; import android.content.Intent; import android.net.Uri; -import android.os.Looper; import android.service.notification.Condition; import android.service.notification.ScheduleCalendar; import android.service.notification.ZenModeConfig; -import android.support.test.InstrumentationRegistry; -import android.test.ServiceTestCase; -import android.testing.TestableContext; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import java.util.Calendar; import java.util.GregorianCalendar; -public class ScheduleConditionProviderTest extends ServiceTestCase<ScheduleConditionProvider> { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ScheduleConditionProviderTest extends NotificationTestCase { ScheduleConditionProvider mService; - @Rule - public final TestableContext mContext = - new TestableContext(InstrumentationRegistry.getContext(), null); - - public ScheduleConditionProviderTest() { - super(ScheduleConditionProvider.class); - } - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - if (Looper.myLooper() == null) { - Looper.prepare(); - } Intent startIntent = new Intent("com.android.server.notification.ScheduleConditionProvider"); startIntent.setPackage("android"); - bindService(startIntent); - mService = spy(getService()); + ScheduleConditionProvider service = new ScheduleConditionProvider(); + service.attach( + getContext(), + null, // ActivityThread not actually used in Service + ScheduleConditionProvider.class.getName(), + null, // token not needed when not talking with the activity manager + null, + null // mocked services don't talk with the activity manager + ); + service.onCreate(); + service.onBind(startIntent); + mService = spy(service); } @Test diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 07b21fbc8f5f..07b21fbc8f5f 100644 --- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java index 4ac0c65791fd..4ac0c65791fd 100644 --- a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java diff --git a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 8ac6481e69d9..8ac6481e69d9 100644 --- a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 4527879e0645..3d20a647c7ec 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -16,10 +16,12 @@ package com.android.server.usage; +import static android.app.usage.UsageStatsManager.REASON_DEFAULT; import static android.app.usage.UsageStatsManager.REASON_FORCED; import static android.app.usage.UsageStatsManager.REASON_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_USAGE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; +import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; @@ -378,8 +380,12 @@ public class AppStandbyController { Slog.d(TAG, " Checking idle state for " + packageName); } if (isSpecial) { + synchronized (mAppIdleLock) { + mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, + STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT); + } maybeInformListeners(packageName, userId, elapsedRealtime, - STANDBY_BUCKET_ACTIVE); + STANDBY_BUCKET_EXEMPTED); } else { synchronized (mAppIdleLock) { String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName, @@ -389,7 +395,8 @@ public class AppStandbyController { continue; } // If the bucket was moved up due to usage, let the timeouts apply. - if (REASON_USAGE.equals(bucketingReason) + if (REASON_DEFAULT.equals(bucketingReason) + || REASON_USAGE.equals(bucketingReason) || REASON_TIMEOUT.equals(bucketingReason)) { int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); @@ -886,6 +893,11 @@ public class AppStandbyController { String packageName = pi.packageName; if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) { mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime); + if (isAppSpecial(packageName, UserHandle.getAppId(pi.applicationInfo.uid), + userId)) { + mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, + STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT); + } } } } diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index dd2e19297272..e76d2113a62e 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -29,18 +29,21 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usb.descriptors.UsbDescriptorParser; +import com.android.server.usb.descriptors.UsbDeviceDescriptor; import com.android.server.usb.descriptors.report.TextReportCanvas; import com.android.server.usb.descriptors.tree.UsbDescriptorsTree; -import java.util.Collection; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; +import java.util.LinkedList; /** * UsbHostManager manages USB state in host mode. */ public class UsbHostManager { private static final String TAG = UsbHostManager.class.getSimpleName(); - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private final Context mContext; @@ -63,6 +66,76 @@ public class UsbHostManager { @GuardedBy("mHandlerLock") private ComponentName mUsbDeviceConnectionHandler; + /* + * Member used for tracking connections & disconnections + */ + static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS"); + private static final int MAX_CONNECT_RECORDS = 32; + private int mNumConnects; // TOTAL # of connect/disconnect + private final LinkedList<ConnectionRecord> mConnections = new LinkedList<ConnectionRecord>(); + private ConnectionRecord mLastConnect; + + /* + * ConnectionRecord + * Stores connection/disconnection data. + */ + class ConnectionRecord { + long mTimestamp; // Same time-base as system log. + String mDeviceAddress; + + static final int CONNECT = 0; + static final int DISCONNECT = 1; + final int mMode; + final byte[] mDescriptors; + + ConnectionRecord(String deviceAddress, int mode, byte[] descriptors) { + mTimestamp = System.currentTimeMillis(); + mDeviceAddress = deviceAddress; + mMode = mode; + mDescriptors = descriptors; + } + + private String formatTime() { + return (new StringBuilder(sFormat.format(new Date(mTimestamp)))).toString(); + } + + void dumpShort(IndentingPrintWriter pw) { + if (mMode == CONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress); + UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); + + UsbDeviceDescriptor deviceDescriptor = parser.getDeviceDescriptor(); + + pw.println("manfacturer:0x" + Integer.toHexString(deviceDescriptor.getVendorID()) + + " product:" + Integer.toHexString(deviceDescriptor.getProductID())); + pw.println("isHeadset[in: " + parser.isInputHeadset() + + " , out: " + parser.isOutputHeadset() + "]"); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } + + void dumpLong(IndentingPrintWriter pw) { + if (mMode == CONNECT) { + pw.println(formatTime() + " Connect " + mDeviceAddress); + UsbDescriptorParser parser = new UsbDescriptorParser(mDeviceAddress, mDescriptors); + StringBuilder stringBuilder = new StringBuilder(); + UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree(); + descriptorTree.parse(parser); + descriptorTree.report(new TextReportCanvas(parser, stringBuilder)); + + stringBuilder.append("isHeadset[in: " + parser.isInputHeadset() + + " , out: " + parser.isOutputHeadset() + "]"); + pw.println(stringBuilder.toString()); + } else { + pw.println(formatTime() + " Disconnect " + mDeviceAddress); + } + } + } + + /* + * UsbHostManager + */ public UsbHostManager(Context context, UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) { mContext = context; @@ -124,6 +197,19 @@ public class UsbHostManager { } + private void addConnectionRecord(String deviceAddress, int mode, byte[] rawDescriptors) { + mNumConnects++; + while (mConnections.size() >= MAX_CONNECT_RECORDS) { + mConnections.removeFirst(); + } + ConnectionRecord rec = + new ConnectionRecord(deviceAddress, mode, rawDescriptors); + mConnections.add(rec); + if (mode == ConnectionRecord.CONNECT) { + mLastConnect = rec; + } + } + /* Called from JNI in monitorUsbHostBus() to report new USB devices Returns true if successful, i.e. the USB Audio device descriptors are correctly parsed and the unique device is added to the audio device list. @@ -174,6 +260,10 @@ public class UsbHostManager { + " , out: " + isOutputHeadset + "]"); mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset); + + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT, + parser.getRawDescriptors()); } else { Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress); return false; @@ -196,6 +286,9 @@ public class UsbHostManager { mUsbAlsaManager.usbDeviceRemoved(device); mSettingsManager.usbDeviceRemoved(device); getCurrentUserSettings().usbDeviceRemoved(device); + + // Tracking + addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null); } } } @@ -249,26 +342,15 @@ public class UsbHostManager { pw.println(" " + name + ": " + mDevices.get(name)); } - Collection<UsbDevice> devices = mDevices.values(); - if (devices.size() != 0) { - pw.println("USB Peripheral Descriptors"); - for (UsbDevice device : devices) { - StringBuilder stringBuilder = new StringBuilder(); - - UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName()); - if (parser.parseDevice()) { - UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree(); - descriptorTree.parse(parser); - - descriptorTree.report(new TextReportCanvas(parser, stringBuilder)); - - stringBuilder.append("isHeadset[in: " + parser.isInputHeadset() - + " , out: " + parser.isOutputHeadset() + "]"); - } else { - stringBuilder.append("Error Parsing USB Descriptors"); - } - pw.println(stringBuilder.toString()); - } + pw.println("" + mNumConnects + " total connects/disconnects"); + pw.println("Last " + mConnections.size() + " connections/disconnections"); + for (ConnectionRecord rec : mConnections) { + rec.dumpShort(pw); + } + + if (mLastConnect != null) { + pw.println("Last Connected USB Device:"); + mLastConnect.dumpLong(pw); } } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 6c6bd01316af..78c7fdc91526 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -32,7 +32,7 @@ public final class UsbDescriptorParser { // Descriptor Objects private static final int DESCRIPTORS_ALLOC_SIZE = 128; - private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>(); + private final ArrayList<UsbDescriptor> mDescriptors; private UsbDeviceDescriptor mDeviceDescriptor; private UsbConfigDescriptor mCurConfigDescriptor; @@ -45,6 +45,28 @@ public final class UsbDescriptorParser { public UsbDescriptorParser(String deviceAddr) { mDeviceAddr = deviceAddr; + mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE); + } + + /** + * Connect this parser to an existing set of already parsed descriptors. + * This is useful for reporting. + */ + public UsbDescriptorParser(String deviceAddr, ArrayList<UsbDescriptor> descriptors) { + mDeviceAddr = deviceAddr; + mDescriptors = descriptors; + //TODO some error checking here.... + mDeviceDescriptor = (UsbDeviceDescriptor) descriptors.get(0); + } + + /** + * Connect this parser to an byte array containing unparsed (raw) device descriptors + * to be parsed (and parse them). Useful for parsing a stored descriptor buffer. + */ + public UsbDescriptorParser(String deviceAddr, byte[] rawDescriptors) { + mDeviceAddr = deviceAddr; + mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE); + parseDescriptors(rawDescriptors); } public String getDeviceAddr() { @@ -196,8 +218,6 @@ public final class UsbDescriptorParser { if (DEBUG) { Log.d(TAG, "parseDescriptors() - start"); } - // This will allow us to (probably) alloc mDescriptors just once. - mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE); ByteStream stream = new ByteStream(descriptors); while (stream.available() > 0) { @@ -241,7 +261,7 @@ public final class UsbDescriptorParser { ? parseDescriptors(rawDescriptors) : false; } - private byte[] getRawDescriptors() { + public byte[] getRawDescriptors() { return getRawDescriptors_native(mDeviceAddr); } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 28342018b0aa..70016157960a 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -143,6 +143,8 @@ public abstract class ConnectionService extends Service { private static final String SESSION_START_RTT = "CS.+RTT"; private static final String SESSION_STOP_RTT = "CS.-RTT"; private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR"; + private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL"; + private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG"; private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1; private static final int MSG_CREATE_CONNECTION = 2; @@ -172,6 +174,8 @@ public abstract class ConnectionService extends Service { private static final int MSG_ON_STOP_RTT = 27; private static final int MSG_RTT_UPGRADE_RESPONSE = 28; private static final int MSG_CREATE_CONNECTION_COMPLETE = 29; + private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30; + private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31; private static Connection sNullConnection; @@ -591,6 +595,26 @@ public abstract class ConnectionService extends Service { Log.endSession(); } } + + @Override + public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException { + Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_LOST); + try { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_LOST).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override + public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException { + Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_GAINED); + try { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_GAINED).sendToTarget(); + } finally { + Log.endSession(); + } + } }; private final Handler mHandler = new Handler(Looper.getMainLooper()) { @@ -1012,6 +1036,12 @@ public abstract class ConnectionService extends Service { } break; } + case MSG_CONNECTION_SERVICE_FOCUS_GAINED: + onConnectionServiceFocusGained(); + break; + case MSG_CONNECTION_SERVICE_FOCUS_LOST: + onConnectionServiceFocusLost(); + break; default: break; } @@ -1873,6 +1903,16 @@ public abstract class ConnectionService extends Service { } /** + * Call to inform Telecom that your {@link ConnectionService} has released call resources (e.g + * microphone, camera). + * + * @see ConnectionService#onConnectionServiceFocusLost() + */ + public final void connectionServiceFocusReleased() { + mAdapter.onConnectionServiceFocusReleased(); + } + + /** * Adds a connection created by the {@link ConnectionService} and informs telecom of the new * connection. * @@ -2146,6 +2186,20 @@ public abstract class ConnectionService extends Service { public void onRemoteExistingConnectionAdded(RemoteConnection connection) {} /** + * Called when the {@link ConnectionService} has lost the call focus. + * The {@link ConnectionService} should release the call resources and invokes + * {@link ConnectionService#connectionServiceFocusReleased()} to inform telecom that it has + * released the call resources. + */ + public void onConnectionServiceFocusLost() {} + + /** + * Called when the {@link ConnectionService} has gained the call focus. The + * {@link ConnectionService} can acquire the call resources at this time. + */ + public void onConnectionServiceFocusGained() {} + + /** * @hide */ public boolean containsConference(Conference conference) { diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java index 92a9dc2303c8..0d319bbc1d2a 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java @@ -628,4 +628,17 @@ final class ConnectionServiceAdapter implements DeathRecipient { } } } + + /** + * Notifies Telecom that the {@link ConnectionService} has released the call resource. + */ + void onConnectionServiceFocusReleased() { + for (IConnectionServiceAdapter adapter : mAdapters) { + try { + Log.d(this, "onConnectionServiceFocusReleased"); + adapter.onConnectionServiceFocusReleased(Log.getExternalSession()); + } catch (RemoteException ignored) { + } + } + } } diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java index 3fbdeb1effb0..3e1bf7790304 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java @@ -73,6 +73,7 @@ final class ConnectionServiceAdapterServant { private static final int MSG_ON_RTT_REMOTELY_TERMINATED = 32; private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33; private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34; + private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35; private final IConnectionServiceAdapter mDelegate; @@ -329,6 +330,9 @@ final class ConnectionServiceAdapterServant { } break; } + case MSG_CONNECTION_SERVICE_FOCUS_RELEASED: + mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/); + break; } } }; @@ -601,6 +605,11 @@ final class ConnectionServiceAdapterServant { args.arg2 = pHandle; mHandler.obtainMessage(MSG_SET_PHONE_ACCOUNT_CHANGED, args).sendToTarget(); } + + @Override + public void onConnectionServiceFocusReleased(Session.Info sessionInfo) { + mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_RELEASED).sendToTarget(); + } }; public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) { diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 85906ad116be..59ce590858ee 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -213,6 +213,9 @@ final class RemoteConnectionService { } @Override + public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {} + + @Override public void addConferenceCall( final String callId, ParcelableConference parcel, Session.Info sessionInfo) { RemoteConference conference = new RemoteConference(callId, diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 92d458f13cd1..6dcc3da15882 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -582,13 +582,21 @@ public class TelecomManager { "android.telecom.extra.CALL_BACK_INTENT"; /** + * The dialer activity responsible for placing emergency calls from, for example, a locked + * keyguard. + * @hide + */ + public static final ComponentName EMERGENCY_DIALER_COMPONENT = + ComponentName.createRelative("com.android.phone", ".EmergencyDialer"); + + /** * The following 4 constants define how properties such as phone numbers and names are * displayed to the user. */ /** * Indicates that the address or number of a call is allowed to be displayed for caller ID. - */ + */ public static final int PRESENTATION_ALLOWED = 1; /** diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl index e428286ad1e3..a74056607a24 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl @@ -100,4 +100,8 @@ oneway interface IConnectionService { void respondToRttUpgradeRequest(String callId, in ParcelFileDescriptor fromInCall, in ParcelFileDescriptor toInCall, in Session.Info sessionInfo); + + void connectionServiceFocusLost(in Session.Info sessionInfo); + + void connectionServiceFocusGained(in Session.Info sessionInfo); } diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl index da2015f6b99b..be474bd467ca 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl @@ -119,4 +119,6 @@ oneway interface IConnectionServiceAdapter { void onPhoneAccountChanged(String callId, in PhoneAccountHandle pHandle, in Session.Info sessionInfo); + + void onConnectionServiceFocusReleased(in Session.Info sessionInfo); } diff --git a/telephony/java/android/telephony/data/DataCallResponse.aidl b/telephony/java/android/telephony/data/DataCallResponse.aidl new file mode 100644 index 000000000000..e4cfd69a9c67 --- /dev/null +++ b/telephony/java/android/telephony/data/DataCallResponse.aidl @@ -0,0 +1,20 @@ +/* + * Copyright 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. + */ + +/** @hide */ +package android.telephony.data; + +parcelable DataCallResponse; diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java new file mode 100644 index 000000000000..8cdad3f24ee5 --- /dev/null +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright (C) 2009 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.telephony.data; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +/** + * Description of the response of a setup data call connection request. + * + * @hide + */ +@SystemApi +public final class DataCallResponse implements Parcelable { + private final int mStatus; + private final int mSuggestedRetryTime; + private final int mCid; + private final int mActive; + private final String mType; + private final String mIfname; + private final List<InterfaceAddress> mAddresses; + private final List<InetAddress> mDnses; + private final List<InetAddress> mGateways; + private final List<String> mPcscfs; + private final int mMtu; + + /** + * @param status Data call fail cause. 0 indicates no error. + * @param suggestedRetryTime The suggested data retry time in milliseconds. + * @param cid The unique id of the data connection. + * @param active Data connection active status. 0 = inactive, 1 = active/physical link down, + * 2 = active/physical link up. + * @param type The connection protocol, should be one of the PDP_type values in TS 27.007 + * section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + * @param ifname The network interface name. + * @param addresses A list of addresses with optional "/" prefix length, e.g., + * "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64". Typically 1 IPv4 or 1 IPv6 or + * one of each. If the prefix length is absent the addresses are assumed to be + * point to point with IPv4 having a prefix length of 32 and IPv6 128. + * @param dnses A list of DNS server addresses, e.g., "192.0.1.3" or + * "192.0.1.11 2001:db8::1". Null if no dns server addresses returned. + * @param gateways A list of default gateway addresses, e.g., "192.0.1.3" or + * "192.0.1.11 2001:db8::1". When null, the addresses represent point to point + * connections. + * @param pcscfs A list of Proxy Call State Control Function address via PCO(Protocol + * Configuration Option) for IMS client. + * @param mtu MTU (Maximum transmission unit) received from network Value <= 0 means network has + * either not sent a value or sent an invalid value. + */ + public DataCallResponse(int status, int suggestedRetryTime, int cid, int active, + @Nullable String type, @Nullable String ifname, + @Nullable List<InterfaceAddress> addresses, + @Nullable List<InetAddress> dnses, + @Nullable List<InetAddress> gateways, + @Nullable List<String> pcscfs, int mtu) { + mStatus = status; + mSuggestedRetryTime = suggestedRetryTime; + mCid = cid; + mActive = active; + mType = (type == null) ? "" : type; + mIfname = (ifname == null) ? "" : ifname; + mAddresses = (addresses == null) ? new ArrayList<>() : addresses; + mDnses = (dnses == null) ? new ArrayList<>() : dnses; + mGateways = (gateways == null) ? new ArrayList<>() : gateways; + mPcscfs = (pcscfs == null) ? new ArrayList<>() : pcscfs; + mMtu = mtu; + } + + public DataCallResponse(Parcel source) { + mStatus = source.readInt(); + mSuggestedRetryTime = source.readInt(); + mCid = source.readInt(); + mActive = source.readInt(); + mType = source.readString(); + mIfname = source.readString(); + mAddresses = new ArrayList<>(); + source.readList(mAddresses, InterfaceAddress.class.getClassLoader()); + mDnses = new ArrayList<>(); + source.readList(mDnses, InetAddress.class.getClassLoader()); + mGateways = new ArrayList<>(); + source.readList(mGateways, InetAddress.class.getClassLoader()); + mPcscfs = new ArrayList<>(); + source.readList(mPcscfs, InetAddress.class.getClassLoader()); + mMtu = source.readInt(); + } + + /** + * @return Data call fail cause. 0 indicates no error. + */ + public int getStatus() { return mStatus; } + + /** + * @return The suggested data retry time in milliseconds. + */ + public int getSuggestedRetryTime() { return mSuggestedRetryTime; } + + + /** + * @return The unique id of the data connection. + */ + public int getCallId() { return mCid; } + + /** + * @return 0 = inactive, 1 = active/physical link down, 2 = active/physical link up. + */ + public int getActive() { return mActive; } + + /** + * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section + * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + */ + @NonNull + public String getType() { return mType; } + + /** + * @return The network interface name. + */ + @NonNull + public String getIfname() { return mIfname; } + + /** + * @return A list of {@link InterfaceAddress} + */ + @NonNull + public List<InterfaceAddress> getAddresses() { return mAddresses; } + + /** + * @return A list of DNS server addresses, e.g., "192.0.1.3" or + * "192.0.1.11 2001:db8::1". Empty list if no dns server addresses returned. + */ + @NonNull + public List<InetAddress> getDnses() { return mDnses; } + + /** + * @return A list of default gateway addresses, e.g., "192.0.1.3" or + * "192.0.1.11 2001:db8::1". Empty list if the addresses represent point to point connections. + */ + @NonNull + public List<InetAddress> getGateways() { return mGateways; } + + /** + * @return A list of Proxy Call State Control Function address via PCO(Protocol Configuration + * Option) for IMS client. + */ + @NonNull + public List<String> getPcscfs() { return mPcscfs; } + + /** + * @return MTU received from network Value <= 0 means network has either not sent a value or + * sent an invalid value + */ + public int getMtu() { return mMtu; } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("DataCallResponse: {") + .append(" status=").append(mStatus) + .append(" retry=").append(mSuggestedRetryTime) + .append(" cid=").append(mCid) + .append(" active=").append(mActive) + .append(" type=").append(mType) + .append(" ifname=").append(mIfname) + .append(" mtu=").append(mMtu) + .append(" addresses=").append(mAddresses) + .append(" dnses=").append(mDnses) + .append(" gateways=").append(mGateways) + .append(" pcscf=").append(mPcscfs) + .append("}"); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mStatus); + dest.writeInt(mSuggestedRetryTime); + dest.writeInt(mCid); + dest.writeInt(mActive); + dest.writeString(mType); + dest.writeString(mIfname); + dest.writeList(mAddresses); + dest.writeList(mDnses); + dest.writeList(mGateways); + dest.writeList(mPcscfs); + dest.writeInt(mMtu); + } + + public static final Parcelable.Creator<DataCallResponse> CREATOR = + new Parcelable.Creator<DataCallResponse>() { + @Override + public DataCallResponse createFromParcel(Parcel source) { + return new DataCallResponse(source); + } + + @Override + public DataCallResponse[] newArray(int size) { + return new DataCallResponse[size]; + } + }; +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/data/InterfaceAddress.aidl b/telephony/java/android/telephony/data/InterfaceAddress.aidl new file mode 100644 index 000000000000..d750363b9cd2 --- /dev/null +++ b/telephony/java/android/telephony/data/InterfaceAddress.aidl @@ -0,0 +1,20 @@ +/* + * Copyright 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. + */ + +/** @hide */ +package android.telephony.data; + +parcelable InterfaceAddress; diff --git a/telephony/java/android/telephony/data/InterfaceAddress.java b/telephony/java/android/telephony/data/InterfaceAddress.java new file mode 100644 index 000000000000..947d0ff4693a --- /dev/null +++ b/telephony/java/android/telephony/data/InterfaceAddress.java @@ -0,0 +1,110 @@ +/* + * Copyright 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.telephony.data; + +import android.annotation.SystemApi; +import android.net.NetworkUtils; +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * This class represents a Network Interface address. In short it's an IP address, a subnet mask + * when the address is an IPv4 one. An IP address and a network prefix length in the case of IPv6 + * address. + * + * @hide + */ +@SystemApi +public final class InterfaceAddress implements Parcelable { + + private final InetAddress mInetAddress; + + private final int mPrefixLength; + + /** + * @param inetAddress A {@link InetAddress} of the address + * @param prefixLength The network prefix length for this address. + */ + public InterfaceAddress(InetAddress inetAddress, int prefixLength) { + mInetAddress = inetAddress; + mPrefixLength = prefixLength; + } + + /** + * @param address The address in string format + * @param prefixLength The network prefix length for this address. + * @throws UnknownHostException + */ + public InterfaceAddress(String address, int prefixLength) throws UnknownHostException { + InetAddress ia; + try { + ia = NetworkUtils.numericToInetAddress(address); + } catch (IllegalArgumentException e) { + throw new UnknownHostException("Non-numeric ip addr=" + address); + } + mInetAddress = ia; + mPrefixLength = prefixLength; + } + + public InterfaceAddress(Parcel source) { + mInetAddress = (InetAddress) source.readSerializable(); + mPrefixLength = source.readInt(); + } + + /** + * @return an InetAddress for this address. + */ + public InetAddress getAddress() { return mInetAddress; } + + /** + * @return The network prefix length for this address. + */ + public int getNetworkPrefixLength() { return mPrefixLength; } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return mInetAddress + "/" + mPrefixLength; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(mInetAddress); + dest.writeInt(mPrefixLength); + } + + public static final Parcelable.Creator<InterfaceAddress> CREATOR = + new Parcelable.Creator<InterfaceAddress>() { + @Override + public InterfaceAddress createFromParcel(Parcel source) { + return new InterfaceAddress(source); + } + + @Override + public InterfaceAddress[] newArray(int size) { + return new InterfaceAddress[size]; + } + }; +} diff --git a/test-base/Android.mk b/test-base/Android.mk index 6a1ac9eac3c9..03bdcf237873 100644 --- a/test-base/Android.mk +++ b/test-base/Android.mk @@ -60,6 +60,9 @@ LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt include $(BUILD_STATIC_JAVA_LIBRARY) +# For unbundled build we'll use the prebuilt jar from prebuilts/sdk. +ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK))) + # Generate the stub source files for android.test.base.stubs # ========================================================== include $(CLEAR_VARS) @@ -151,6 +154,8 @@ update-android-test-base-api: $(ANDROID_TEST_BASE_OUTPUT_API_FILE) | $(ACP) @echo Copying removed.txt $(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE) +endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true + # Build the legacy-android-test library # ===================================== # This contains the android.test classes that were in Android API level 25, diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk index d01b1f96ee05..09739e5e074a 100644 --- a/tests/AppLaunch/Android.mk +++ b/tests/AppLaunch/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := AppLaunch LOCAL_CERTIFICATE := platform -LOCAL_JAVA_LIBRARIES := legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := android-support-test diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk index 527d1bbfd886..9e7f61892f93 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk @@ -24,7 +24,7 @@ LOCAL_PACKAGE_NAME := SmartCamera-tests LOCAL_SRC_FILES += $(call all-java-files-under, src) -LOCAL_JAVA_LIBRARIES := legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.base LOCAL_STATIC_JAVA_LIBRARIES := guava junit LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk index d1f845623be8..f7b34523c086 100644 --- a/tests/ServiceCrashTest/Android.mk +++ b/tests/ServiceCrashTest/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ServiceCrashTest LOCAL_CERTIFICATE := platform -LOCAL_JAVA_LIBRARIES := legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.base LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test diff --git a/tests/net/Android.mk b/tests/net/Android.mk index 677585cc0c0f..1bd1af5e3c22 100644 --- a/tests/net/Android.mk +++ b/tests/net/Android.mk @@ -21,7 +21,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ services.net LOCAL_JAVA_LIBRARIES := \ - android.test.runner + android.test.runner \ + android.test.base \ + android.test.mock LOCAL_PACKAGE_NAME := FrameworksNetTests LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk index 0e36981e3716..7fcfc6eb82d3 100644 --- a/tests/testables/Android.mk +++ b/tests/testables/Android.mk @@ -25,10 +25,9 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ - mockito-target-minus-junit4 \ - legacy-android-test + mockito-target-minus-junit4 -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.mock include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk index 43d1e37cafa3..543c652dc24a 100644 --- a/tests/utils/testutils/Android.mk +++ b/tests/utils/testutils/Android.mk @@ -25,9 +25,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under,java) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ - legacy-android-test \ mockito-target-minus-junit4 -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp index dc5c14e32cbd..4e9391db9a5b 100644 --- a/tools/streaming_proto/Android.bp +++ b/tools/streaming_proto/Android.bp @@ -24,6 +24,10 @@ cc_defaults { "stream_proto_utils.cpp", "string_utils.cpp", ], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: ["libprotoc"], } diff --git a/tools/streaming_proto/stream_proto_utils.cpp b/tools/streaming_proto/stream_proto_utils.cpp index e8f86bc0be83..fb2d98d45b0e 100644 --- a/tools/streaming_proto/stream_proto_utils.cpp +++ b/tools/streaming_proto/stream_proto_utils.cpp @@ -13,8 +13,6 @@ const uint64_t FIELD_TYPE_SHIFT = 32; // TODO: packed is not supported yet. // const uint64_t FIELD_COUNT_SHIFT = 40; -const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT; -const uint64_t FIELD_COUNT_UNKNOWN = 0; const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT; const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT; const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT; diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk index c98e40a2c2d9..d9f332f2f3bd 100644 --- a/wifi/tests/Android.mk +++ b/wifi/tests/Android.mk @@ -58,6 +58,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ + android.test.base \ LOCAL_PACKAGE_NAME := FrameworksWifiApiTests LOCAL_COMPATIBILITY_SUITE := device-tests |