diff options
102 files changed, 1698 insertions, 389 deletions
diff --git a/Android.bp b/Android.bp index 7fac01a0f3b9..763d242a12f9 100644 --- a/Android.bp +++ b/Android.bp @@ -602,6 +602,7 @@ java_library { "core/java/android/speech/tts/EventLogTags.logtags", "core/java/android/net/EventLogTags.logtags", "core/java/android/webkit/EventLogTags.logtags", + "core/java/com/android/internal/app/EventLogTags.logtags", "core/java/com/android/internal/logging/EventLogTags.logtags", "core/java/com/android/server/DropboxLogTags.logtags", "core/java/org/chromium/arc/EventLogTags.logtags", diff --git a/Android.mk b/Android.mk index 32e4bfa57030..35b5f92be310 100644 --- a/Android.mk +++ b/Android.mk @@ -825,6 +825,16 @@ include $(BUILD_STATIC_JAVA_LIBRARY) # ==== hiddenapi lists ======================================= +# Copy blacklist and dark greylist over into the build folder. +# This is for ART buildbots which need to mock these lists and have alternative +# rules for building them. Other rules in the build system should depend on the +# files in the build folder. + +$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\ + $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))) +$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-dark-greylist.txt,\ + $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))) + # Generate light greylist as private API minus (blacklist plus dark greylist). $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) diff --git a/api/system-current.txt b/api/system-current.txt index b38492092d8f..663ad112280a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -781,6 +781,7 @@ package android.content { field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score"; field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock"; field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; + field public static final java.lang.String SECURE_ELEMENT_SERVICE = "secure_element"; field public static final java.lang.String STATS_MANAGER = "stats"; field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final java.lang.String VR_SERVICE = "vrmanager"; @@ -3523,12 +3524,17 @@ package android.os { public class HidlSupport { method public static boolean deepEquals(java.lang.Object, java.lang.Object); method public static int deepHashCode(java.lang.Object); + method public static int getPidIfSharable(); method public static boolean interfacesEqual(android.os.IHwInterface, java.lang.Object); } public abstract class HwBinder implements android.os.IHwBinder { method public static final void configureRpcThreadpool(long, boolean); + method public static void enableInstrumentation(); + method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException; + method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException; method public static final void joinRpcThreadpool(); + method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException; } public class HwBlob { @@ -3628,6 +3634,8 @@ package android.os { public abstract interface IHwBinder { method public abstract boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long); + method public abstract android.os.IHwInterface queryLocalInterface(java.lang.String); + method public abstract void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException; method public abstract boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient); } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 8f0a44a68a4b..99e871f0849f 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -837,15 +837,7 @@ message AppStartChanged { // Device uptime when activity started. optional int64 activity_start_msec = 7; - // TODO: Update android/app/ActivityManagerInternal.java constants to depend on our proto enum. - enum TransitionReason { - APP_START_TRANSITION_REASON_UNKNOWN = 0; - SPLASH_SCREEN = 1; - WINDOWS_DRAWN = 2; - TIMEOUT = 3; - SNAPSHOT = 4; - } - optional TransitionReason reason = 8; + optional android.app.AppTransitionReasonEnum reason = 8; optional int32 transition_delay_msec = 9; // -1 if not set. diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index da9f72855e09..5ee7edee9db7 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -43,25 +43,29 @@ public abstract class ActivityManagerInternal { * Type for {@link #notifyAppTransitionStarting}: The transition was started because we drew * the splash screen. */ - public static final int APP_TRANSITION_SPLASH_SCREEN = 1; + public static final int APP_TRANSITION_SPLASH_SCREEN = + AppProtoEnums.APP_TRANSITION_SPLASH_SCREEN; // 1 /** * Type for {@link #notifyAppTransitionStarting}: The transition was started because we all * app windows were drawn */ - public static final int APP_TRANSITION_WINDOWS_DRAWN = 2; + public static final int APP_TRANSITION_WINDOWS_DRAWN = + AppProtoEnums.APP_TRANSITION_WINDOWS_DRAWN; // 2 /** * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a * timeout. */ - public static final int APP_TRANSITION_TIMEOUT = 3; + public static final int APP_TRANSITION_TIMEOUT = + AppProtoEnums.APP_TRANSITION_TIMEOUT; // 3 /** * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a * we drew a task snapshot. */ - public static final int APP_TRANSITION_SNAPSHOT = 4; + public static final int APP_TRANSITION_SNAPSHOT = + AppProtoEnums.APP_TRANSITION_SNAPSHOT; // 4 /** * The bundle key to extract the assist data. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 934b0f3cd4e4..3dedeea1a1b0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5114,6 +5114,8 @@ public final class ActivityThread extends ClientTransactionHandler { // as that method uses the same check on the activity config override as well. final boolean equivalent = config != null && mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config)); + final Theme systemTheme = getSystemContext().getTheme(); + final Theme systemUiTheme = getSystemUiContext().getTheme(); synchronized (mResourcesManager) { if (mPendingConfiguration != null) { @@ -5146,12 +5148,10 @@ public final class ActivityThread extends ClientTransactionHandler { configDiff = mConfiguration.updateFrom(config); config = applyCompatConfiguration(mCurDefaultDisplayDpi); - final Theme systemTheme = getSystemContext().getTheme(); if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { systemTheme.rebase(); } - final Theme systemUiTheme = getSystemUiContext().getTheme(); if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { systemUiTheme.rebase(); } diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index cba9dcc3c4cc..a1ad825c3a29 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -256,6 +256,14 @@ public class JobInfo implements Parcelable { public static final int FLAG_IS_PREFETCH = 1 << 2; /** + * This job needs to be exempted from the app standby throttling. Only the system (UID 1000) + * can set it. Jobs with a time constrant must not have it. + * + * @hide + */ + public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3; + + /** * @hide */ public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0; @@ -355,6 +363,13 @@ public class JobInfo implements Parcelable { return flags; } + /** @hide */ + public boolean isExemptedFromAppStandby() { + return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) + && !hasEarlyConstraint() + && !hasLateConstraint(); + } + /** * Whether this job requires that the device be charging (or be a non-battery-powered * device connected to permanent power, such as Android TV devices). diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index bd978e3df863..5d6a989ffef8 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -146,6 +146,14 @@ public abstract class UsageStatsManagerInternal { * allowed to do work even if they're idle or in a low bucket. */ public abstract void onParoleStateChanged(boolean isParoleOn); + + /** + * Optional callback to inform the listener that the app has transitioned into + * an active state due to user interaction. + */ + public void onUserInteractionStarted(String packageName, @UserIdInt int userId) { + // No-op by default + } } /** Backup/Restore API */ @@ -212,4 +220,17 @@ public abstract class UsageStatsManagerInternal { * indicated here before by a call to {@link #setLastJobRunTime(String, int, long)}. */ public abstract long getTimeSinceLastJobRun(String packageName, @UserIdInt int userId); + + /** + * Report a few data points about an app's job state at the current time. + * + * @param packageName the app whose job state is being described + * @param userId which user the app is associated with + * @param numDeferredJobs the number of pending jobs that were deferred + * due to bucketing policy + * @param timeSinceLastJobRun number of milliseconds since the last time one of + * this app's jobs was executed + */ + public abstract void reportAppJobState(String packageName, @UserIdInt int userId, + int numDeferredJobs, long timeSinceLastJobRun); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5177e102425a..f2eb4a0285a4 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4170,6 +4170,16 @@ public abstract class Context { public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps"; /** + * Use with {@link #getSystemService} to retrieve a + * {@link android.se.omapi.ISecureElementService} + * for accessing the SecureElementService. + * + * @hide + */ + @SystemApi + public static final String SECURE_ELEMENT_SERVICE = "secure_element"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java index 335bf9d86fc7..91b796aba655 100644 --- a/core/java/android/os/HidlSupport.java +++ b/core/java/android/os/HidlSupport.java @@ -212,9 +212,10 @@ public class HidlSupport { } /** - * Return PID of process if sharable to clients. + * Return PID of process only if on a non-user build. For debugging purposes. * @hide */ + @SystemApi public static native int getPidIfSharable(); /** @hide */ diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index ecac002940cc..2a088a659b0f 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -53,14 +53,30 @@ public abstract class HwBinder implements IHwBinder { public native final void registerService(String serviceName) throws RemoteException; - /** @hide */ + /** + * Returns the specified service from the hwservicemanager. Does not retry. + * + * @param iface fully-qualified interface name for example foo.bar@1.3::IBaz + * @param serviceName the instance name of the service for example default. + * @throws NoSuchElementException when the service is unavailable + * @hide + */ + @SystemApi public static final IHwBinder getService( String iface, String serviceName) throws RemoteException, NoSuchElementException { return getService(iface, serviceName, false /* retry */); } - /** @hide */ + /** + * Returns the specified service from the hwservicemanager. + * @param iface fully-qualified interface name for example foo.bar@1.3::IBaz + * @param serviceName the instance name of the service for example default. + * @param retry whether to wait for the service to start if it's not already started + * @throws NoSuchElementException when the service is unavailable + * @hide + */ + @SystemApi public static native final IHwBinder getService( String iface, String serviceName, @@ -108,7 +124,19 @@ public abstract class HwBinder implements IHwBinder { private static native void native_report_sysprop_change(); /** + * Enable instrumentation if available. + * @hide + */ + @SystemApi + public static void enableInstrumentation() { + native_report_sysprop_change(); + } + + /** * Notifies listeners that a system property has changed + * + * TODO(b/72480743): remove this method + * * @hide */ public static void reportSyspropChanged() { diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java index ce9f6c1654c2..0c592e1f04b8 100644 --- a/core/java/android/os/IHwBinder.java +++ b/core/java/android/os/IHwBinder.java @@ -27,12 +27,22 @@ public interface IHwBinder { /** @hide */ public static final int FLAG_ONEWAY = 1; - /** @hide */ + /** + * Process a hwbinder transaction. + * + * @hide + */ + @SystemApi public void transact( int code, HwParcel request, HwParcel reply, int flags) throws RemoteException; - /** @hide */ + /** + * Return as IHwInterface instance only if this implements descriptor. + * @param descriptor for example foo.bar@1.0::IBaz + * @hide + */ + @SystemApi public IHwInterface queryLocalInterface(String descriptor); /** diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 6833908b5c1f..96e2ae3d5ac1 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -157,6 +157,12 @@ public class Process { */ public static final int INCIDENTD_UID = 1067; + /** + * Defines the UID/GID for the Secure Element service process. + * @hide + */ + public static final int SE_UID = 1068; + /** {@hide} */ public static final int NOBODY_UID = 9999; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 26495cd22aff..2440b489f416 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10503,6 +10503,15 @@ public final class Settings { = "forced_app_standby_for_small_battery_enabled"; /** + * Whether or not to enable Time Only Mode for watch type devices. + * Type: int (0 for false, 1 for true) + * Default: 0 + * @hide + */ + public static final String TIME_ONLY_MODE_ENABLED + = "time_only_mode_enabled"; + + /** * Whether or not Network Watchlist feature is enabled. * Type: int (0 for false, 1 for true) * Default: 0 diff --git a/core/java/android/security/keystore/RecoveryController.java b/core/java/android/security/keystore/RecoveryController.java index 8be6d5263c53..98e6a2099012 100644 --- a/core/java/android/security/keystore/RecoveryController.java +++ b/core/java/android/security/keystore/RecoveryController.java @@ -167,7 +167,7 @@ public class RecoveryController { public @NonNull KeychainSnapshot getRecoveryData(@NonNull byte[] account) throws InternalRecoveryServiceException { try { - return BackwardsCompat.toLegacyKeychainSnapshot(mBinder.getRecoveryData(account)); + return BackwardsCompat.toLegacyKeychainSnapshot(mBinder.getKeyChainSnapshot()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index 71a36f19a360..4e4a0374087e 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -171,6 +171,8 @@ public class RecoveryController { } /** + * Deprecated - use getKeyChainSnapshot. + * * Returns data necessary to store all recoverable keys. Key material is * encrypted with user secret and recovery public key. * @@ -179,10 +181,35 @@ public class RecoveryController { * service. */ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) - public @NonNull KeyChainSnapshot getRecoveryData() + public @Nullable KeyChainSnapshot getRecoveryData() + throws InternalRecoveryServiceException { + try { + return mBinder.getKeyChainSnapshot(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_NO_SNAPSHOT_PENDING) { + return null; + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Returns data necessary to store all recoverable keys. Key material is + * encrypted with user secret and recovery public key. + * + * @return Data necessary to recover keystore or {@code null} if snapshot is not available. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) + public @Nullable KeyChainSnapshot getKeyChainSnapshot() throws InternalRecoveryServiceException { try { - return mBinder.getRecoveryData(/*account=*/ new byte[]{}); + return mBinder.getKeyChainSnapshot(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java index 2a352adcee18..b6c6bdc00bbe 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -18,11 +18,11 @@ package android.service.notification; import android.annotation.IntDef; import android.annotation.SystemApi; -import android.app.AutomaticZenRule; import android.content.Context; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; +import android.util.proto.ProtoOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -161,6 +161,22 @@ public final class Condition implements Parcelable { .append(']').toString(); } + /** @hide */ + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + // id is guarantreed not to be null. + proto.write(ConditionProto.ID, id.toString()); + proto.write(ConditionProto.SUMMARY, summary); + proto.write(ConditionProto.LINE_1, line1); + proto.write(ConditionProto.LINE_2, line2); + proto.write(ConditionProto.ICON, icon); + proto.write(ConditionProto.STATE, state); + proto.write(ConditionProto.FLAGS, flags); + + proto.end(token); + } + @SystemApi public static String stateToString(int state) { if (state == STATE_FALSE) return "STATE_FALSE"; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index f658ae03c927..bb88e1a20f73 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -33,6 +33,7 @@ import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.R; @@ -1262,6 +1263,30 @@ public class ZenModeConfig implements Parcelable { .append(']').toString(); } + /** @hide */ + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + proto.write(ZenRuleProto.ID, id); + proto.write(ZenRuleProto.NAME, name); + proto.write(ZenRuleProto.CREATION_TIME_MS, creationTime); + proto.write(ZenRuleProto.ENABLED, enabled); + proto.write(ZenRuleProto.ENABLER, enabler); + proto.write(ZenRuleProto.IS_SNOOZING, snoozing); + proto.write(ZenRuleProto.ZEN_MODE, zenMode); + if (conditionId != null) { + proto.write(ZenRuleProto.CONDITION_ID, conditionId.toString()); + } + if (condition != null) { + condition.writeToProto(proto, ZenRuleProto.CONDITION); + } + if (component != null) { + component.writeToProto(proto, ZenRuleProto.COMPONENT); + } + + proto.end(token); + } + private static void appendDiff(Diff d, String item, ZenRule from, ZenRule to) { if (d == null) return; if (from == null) { diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java index bf335196edef..597089235e6b 100644 --- a/core/java/android/util/MemoryIntArray.java +++ b/core/java/android/util/MemoryIntArray.java @@ -16,13 +16,19 @@ package android.util; +import static android.os.Process.FIRST_APPLICATION_UID; + import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; +import android.os.Process; + +import com.android.internal.annotations.GuardedBy; -import libcore.io.IoUtils; import dalvik.system.CloseGuard; +import libcore.io.IoUtils; + import java.io.Closeable; import java.io.IOException; import java.util.UUID; @@ -49,13 +55,18 @@ import java.util.UUID; */ public final class MemoryIntArray implements Parcelable, Closeable { private static final String TAG = "MemoryIntArray"; + private static final boolean DEBUG = Process.myUid() < FIRST_APPLICATION_UID; private static final int MAX_SIZE = 1024; + private final Object mLock = new Object(); private final CloseGuard mCloseGuard = CloseGuard.get(); private final boolean mIsOwner; private final long mMemoryAddr; + + /** Fd for the shared memory object, -1 when closed */ + @GuardedBy("mLock") private int mFd = -1; /** @@ -74,6 +85,7 @@ public final class MemoryIntArray implements Parcelable, Closeable { mFd = nativeCreate(name, size); mMemoryAddr = nativeOpen(mFd, mIsOwner); mCloseGuard.open("close"); + if (DEBUG) Log.i(TAG, "created " + getString()); } private MemoryIntArray(Parcel parcel) throws IOException { @@ -85,6 +97,8 @@ public final class MemoryIntArray implements Parcelable, Closeable { mFd = pfd.detachFd(); mMemoryAddr = nativeOpen(mFd, mIsOwner); mCloseGuard.open("close"); + + if (DEBUG) Log.i(TAG, "created from parcel " + getString()); } /** @@ -141,13 +155,33 @@ public final class MemoryIntArray implements Parcelable, Closeable { */ @Override public void close() throws IOException { - if (!isClosed()) { - nativeClose(mFd, mMemoryAddr, mIsOwner); - mFd = -1; - mCloseGuard.close(); + synchronized (mLock) { + if (!isClosed()) { + if (DEBUG) { + try { + throw new Exception(); + } catch (Exception here) { + Log.i(TAG, "closing " + getString(), here); + } + } + nativeClose(mFd, mMemoryAddr, mIsOwner); + mFd = -1; + mCloseGuard.close(); + } else { + try { + throw new Exception(); + } catch (Exception here) { + if (DEBUG) Log.i(TAG, getString() + " already closed", here); + } + } } } + private String getString() { + return this.getClass().getSimpleName() + "@" + System.identityHashCode(this) + + " mMemoryAddr=" + mMemoryAddr + " mFd=" + mFd; + } + /** * @return Whether this array is closed and shouldn't be used. */ @@ -162,7 +196,9 @@ public final class MemoryIntArray implements Parcelable, Closeable { mCloseGuard.warnIfOpen(); } - IoUtils.closeQuietly(this); + if (!isClosed()) { + IoUtils.closeQuietly(this); + } } finally { super.finalize(); } @@ -206,7 +242,8 @@ public final class MemoryIntArray implements Parcelable, Closeable { private void enforceNotClosed() { if (isClosed()) { - throw new IllegalStateException("cannot interact with a closed instance"); + throw new IllegalStateException("cannot interact with a closed instance " + + getString()); } } diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index ee6fc072765f..a4c590f1b459 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -477,6 +477,7 @@ public class ApkSignatureSchemeV3Verifier { } } + signedData.rewind(); byte[] encodedCert = readLengthPrefixedByteArray(signedData); int signedSigAlgorithm = signedData.getInt(); if (lastCert != null && lastSigAlgorithm != signedSigAlgorithm) { diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java index ba21ccb808fc..4c6e511ede46 100644 --- a/core/java/android/util/apk/ApkVerityBuilder.java +++ b/core/java/android/util/apk/ApkVerityBuilder.java @@ -308,14 +308,6 @@ abstract class ApkVerityBuilder { return rootHash; } - private static void bufferPut(ByteBuffer buffer, byte value) { - // FIXME(b/72459251): buffer.put(value) does NOT work surprisingly. The position() after put - // does NOT even change. This hack workaround the problem, but the root cause remains - // unkonwn yet. This seems only happen when it goes through the apk install flow on my - // setup. - buffer.put(new byte[] { value }); - } - private static ByteBuffer generateFsverityHeader(ByteBuffer buffer, long fileSize, int depth, byte[] salt) { if (salt.length != 8) { @@ -325,10 +317,10 @@ abstract class ApkVerityBuilder { // TODO(b/30972906): update the reference when there is a better one in public. buffer.put("TrueBrew".getBytes()); // magic - bufferPut(buffer, (byte) 1); // major version - bufferPut(buffer, (byte) 0); // minor version - bufferPut(buffer, (byte) 12); // log2(block-size): log2(4096) - bufferPut(buffer, (byte) 7); // log2(leaves-per-node): log2(4096 / 32) + buffer.put((byte) 1); // major version + buffer.put((byte) 0); // minor version + buffer.put((byte) 12); // log2(block-size): log2(4096) + buffer.put((byte) 7); // log2(leaves-per-node): log2(4096 / 32) buffer.putShort((short) 1); // meta algorithm, SHA256_MODE == 1 buffer.putShort((short) 1); // data algorithm, SHA256_MODE == 1 @@ -338,8 +330,8 @@ abstract class ApkVerityBuilder { buffer.putLong(fileSize); // original file size - bufferPut(buffer, (byte) 0); // auth block offset, disabled here - bufferPut(buffer, (byte) 2); // extension count + buffer.put((byte) 0); // auth block offset, disabled here + buffer.put((byte) 2); // extension count buffer.put(salt); // salt (8 bytes) // skip(buffer, 22); // reserved diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 8b730f282b1b..370c97e37262 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -166,18 +166,6 @@ public final class ThreadedRenderer { public static final String OVERDRAW_PROPERTY_SHOW = "show"; /** - * Defines the rendering pipeline to be used by the ThreadedRenderer. - * - * Possible values: - * "opengl", will use the existing OpenGL renderer - * "skiagl", will use Skia's OpenGL renderer - * "skiavk", will use Skia's Vulkan renderer - * - * @hide - */ - public static final String DEBUG_RENDERER_PROPERTY = "debug.hwui.renderer"; - - /** * Turn on to debug non-rectangular clip operations. * * Possible values: diff --git a/core/java/com/android/internal/app/EventLogTags.logtags b/core/java/com/android/internal/app/EventLogTags.logtags new file mode 100644 index 000000000000..d681a8d26e8e --- /dev/null +++ b/core/java/com/android/internal/app/EventLogTags.logtags @@ -0,0 +1,6 @@ +# See system/core/logcat/event.logtags for a description of the format of this file. + +option java_package com.android.internal.app; + +53000 harmful_app_warning_uninstall (package_name|3) +53001 harmful_app_warning_launch_anyway (package_name|3)
\ No newline at end of file diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java index 042da36c98f1..99666264cb22 100644 --- a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java +++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java @@ -20,8 +20,12 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; +import android.view.View; +import android.widget.TextView; import com.android.internal.R; /** @@ -31,7 +35,7 @@ import com.android.internal.R; */ public class HarmfulAppWarningActivity extends AlertActivity implements DialogInterface.OnClickListener { - private static final String TAG = "HarmfulAppWarningActivity"; + private static final String TAG = HarmfulAppWarningActivity.class.getSimpleName(); private static final String EXTRA_HARMFUL_APP_WARNING = "harmful_app_warning"; @@ -39,13 +43,11 @@ public class HarmfulAppWarningActivity extends AlertActivity implements private String mHarmfulAppWarning; private IntentSender mTarget; - // [b/63909431] STOPSHIP replace placeholder UI with final Harmful App Warning UI - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent intent = getIntent(); + final Intent intent = getIntent(); mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME); mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT); mHarmfulAppWarning = intent.getStringExtra(EXTRA_HARMFUL_APP_WARNING); @@ -55,33 +57,56 @@ public class HarmfulAppWarningActivity extends AlertActivity implements finish(); } - AlertController.AlertParams p = mAlertParams; + final ApplicationInfo applicationInfo; + try { + applicationInfo = getPackageManager().getApplicationInfo(mPackageName, 0 /*flags*/); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not show warning because package does not exist ", e); + finish(); + return; + } + + final AlertController.AlertParams p = mAlertParams; p.mTitle = getString(R.string.harmful_app_warning_title); - p.mMessage = mHarmfulAppWarning; - p.mPositiveButtonText = getString(R.string.harmful_app_warning_launch_anyway); + p.mView = createView(applicationInfo); + + p.mPositiveButtonText = getString(R.string.harmful_app_warning_uninstall); p.mPositiveButtonListener = this; - p.mNegativeButtonText = getString(R.string.harmful_app_warning_uninstall); + p.mNegativeButtonText = getString(R.string.harmful_app_warning_open_anyway); p.mNegativeButtonListener = this; mAlert.installContent(mAlertParams); } + private View createView(ApplicationInfo applicationInfo) { + final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog, + null /*root*/); + ((TextView) view.findViewById(R.id.app_name_text)) + .setText(applicationInfo.loadSafeLabel(getPackageManager())); + ((TextView) view.findViewById(R.id.message)) + .setText(mHarmfulAppWarning); + return view; + } + @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: - getPackageManager().setHarmfulAppWarning(mPackageName, null); + getPackageManager().deletePackage(mPackageName, null /*observer*/, 0 /*flags*/); + EventLogTags.writeHarmfulAppWarningUninstall(mPackageName); + finish(); + break; + case DialogInterface.BUTTON_NEGATIVE: + getPackageManager().setHarmfulAppWarning(mPackageName, null /*warning*/); - IntentSender target = getIntent().getParcelableExtra(Intent.EXTRA_INTENT); + final IntentSender target = getIntent().getParcelableExtra(Intent.EXTRA_INTENT); try { - startIntentSenderForResult(target, -1, null, 0, 0, 0); + startIntentSenderForResult(target, -1 /*requestCode*/, null /*fillInIntent*/, + 0 /*flagsMask*/, 0 /*flagsValue*/, 0 /*extraFlags*/); } catch (IntentSender.SendIntentException e) { - // ignore.. + Log.e(TAG, "Error while starting intent sender", e); } - finish(); - break; - case DialogInterface.BUTTON_NEGATIVE: - getPackageManager().deletePackage(mPackageName, null, 0); + EventLogTags.writeHarmfulAppWarningLaunchAnyway(mPackageName); finish(); break; } @@ -89,7 +114,7 @@ public class HarmfulAppWarningActivity extends AlertActivity implements public static Intent createHarmfulAppWarningIntent(Context context, String targetPackageName, IntentSender target, CharSequence harmfulAppWarning) { - Intent intent = new Intent(); + final Intent intent = new Intent(); intent.setClass(context, HarmfulAppWarningActivity.class); intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName); intent.putExtra(Intent.EXTRA_INTENT, target); diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 927d75753eca..5673814ca362 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -64,7 +64,7 @@ interface ILockSettings { // {@code ServiceSpecificException} may be thrown to signal an error, which caller can // convert to {@code RecoveryManagerException}. void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList); - KeyChainSnapshot getRecoveryData(in byte[] account); + KeyChainSnapshot getKeyChainSnapshot(); byte[] generateAndStoreKey(String alias); void removeKey(String alias); void setSnapshotCreatedPendingIntent(in PendingIntent intent); diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto index 2de2574ad401..5eb05be1a1d1 100644 --- a/core/proto/android/app/enums.proto +++ b/core/proto/android/app/enums.proto @@ -21,6 +21,19 @@ package android.app; option java_outer_classname = "AppProtoEnums"; option java_multiple_files = true; +// ActivityManagerInternal.java's APP_TRANSITION reasons. +enum AppTransitionReasonEnum { + APP_TRANSITION_REASON_UNKNOWN = 0; + // The transition was started because we drew the splash screen. + APP_TRANSITION_SPLASH_SCREEN = 1; + // The transition was started because we all app windows were drawn. + APP_TRANSITION_WINDOWS_DRAWN = 2; + // The transition was started because of a timeout. + APP_TRANSITION_TIMEOUT = 3; + // The transition was started because of a we drew a task snapshot. + APP_TRANSITION_SNAPSHOT = 4; +} + // ActivityManager.java PROCESS_STATEs enum ProcessStateEnum { // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values diff --git a/core/proto/android/app/notification.proto b/core/proto/android/app/notification.proto index 379a4ae8e2ac..c7e313aa5801 100644 --- a/core/proto/android/app/notification.proto +++ b/core/proto/android/app/notification.proto @@ -18,10 +18,10 @@ syntax = "proto2"; option java_package = "android.app"; option java_multiple_files = true; -import "frameworks/base/libs/incident/proto/android/privacy.proto"; - package android.app; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + /** * An android.app.Notification object. * Deprecated fields are not included in the proto. diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto index 0388547e009f..337aa1c20c7a 100644 --- a/core/proto/android/app/notification_channel.proto +++ b/core/proto/android/app/notification_channel.proto @@ -21,19 +21,22 @@ option java_multiple_files = true; package android.app; import "frameworks/base/core/proto/android/media/audioattributes.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; /** * An android.app.NotificationChannel object. */ message NotificationChannelProto { - optional string id = 1; - optional string name = 2; - optional string description = 3; + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string id = 1 [ (android.privacy).dest = DEST_EXPLICIT ]; + optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ]; + optional string description = 3 [ (android.privacy).dest = DEST_EXPLICIT ]; optional int32 importance = 4; optional bool can_bypass_dnd = 5; // Default is VISIBILITY_NO_OVERRIDE (-1000). optional int32 lockscreen_visibility = 6; - optional string sound = 7; + optional string sound = 7 [ (android.privacy).dest = DEST_EXPLICIT ]; optional bool use_lights = 8; // Default is 0. optional int32 light_color = 9; @@ -46,7 +49,7 @@ message NotificationChannelProto { optional bool show_badge = 13; // Default is false. optional bool is_deleted = 14; - optional string group = 15; + optional string group = 15 [ (android.privacy).dest = DEST_EXPLICIT ]; optional android.media.AudioAttributesProto audio_attributes = 16; // If this is a blockable system notification channel. optional bool is_blockable_system = 17; diff --git a/core/proto/android/app/notification_channel_group.proto b/core/proto/android/app/notification_channel_group.proto index 89a540f2012c..7b270d74f2de 100644 --- a/core/proto/android/app/notification_channel_group.proto +++ b/core/proto/android/app/notification_channel_group.proto @@ -21,11 +21,14 @@ option java_multiple_files = true; package android.app; import "frameworks/base/core/proto/android/app/notification_channel.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; /** * An android.app.NotificationChannelGroup object. */ message NotificationChannelGroupProto { + option (.android.msg_privacy).dest = DEST_EXPLICIT; + optional string id = 1; optional string name = 2; optional string description = 3; diff --git a/core/proto/android/app/notificationmanager.proto b/core/proto/android/app/notificationmanager.proto index 7d774aeab551..e991688c218c 100644 --- a/core/proto/android/app/notificationmanager.proto +++ b/core/proto/android/app/notificationmanager.proto @@ -20,10 +20,14 @@ option java_multiple_files = true; package android.app; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + /** - * An android.app.NotificationMananger.Policy object. + * An android.app.NotificationManager.Policy object. */ message PolicyProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + enum Category { CATEGORY_UNKNOWN = 0; // Reminder notifications are prioritized. @@ -36,6 +40,11 @@ message PolicyProto { CALLS = 4; // Calls from repeat callers are prioritized. REPEAT_CALLERS = 5; + // Alarms are prioritized. + ALARMS = 6; + // Media, system, game (catch-all for non-never suppressible sounds) are + // prioritized. + MEDIA_SYSTEM_OTHER = 7; } repeated Category priority_categories = 1; diff --git a/core/proto/android/os/ps.proto b/core/proto/android/os/ps.proto index 88c6609a92b6..9cce7274d000 100644 --- a/core/proto/android/os/ps.proto +++ b/core/proto/android/os/ps.proto @@ -20,10 +20,17 @@ package android.os; option java_multiple_files = true; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + message PsDumpProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + message Process { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + // Security label, most commonly used for SELinux context data. optional string label = 1; + // String representation of uid. optional string user = 2; // Process ID number. optional int32 pid = 3; diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index 65df89a9a85e..9013a23664f6 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -25,8 +25,11 @@ import "frameworks/base/core/proto/android/app/notification_channel_group.proto" import "frameworks/base/core/proto/android/app/notificationmanager.proto"; import "frameworks/base/core/proto/android/content/component_name.proto"; import "frameworks/base/core/proto/android/media/audioattributes.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; message NotificationServiceDumpProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + repeated NotificationRecordProto records = 1; optional ZenModeProto zen = 2; @@ -45,7 +48,9 @@ message NotificationServiceDumpProto { } message NotificationRecordProto { - optional string key = 1; + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string key = 1 [ (.android.privacy).dest = DEST_EXPLICIT ]; enum State { ENQUEUED = 0; @@ -54,21 +59,25 @@ message NotificationRecordProto { } optional State state = 2; optional int32 flags = 3; - optional string channelId = 4; - optional string sound = 5; + optional string channelId = 4 [ (.android.privacy).dest = DEST_EXPLICIT ]; + optional string sound = 5 [ (.android.privacy).dest = DEST_EXPLICIT ]; optional .android.media.AudioAttributesProto audio_attributes = 6; optional bool can_vibrate = 7; optional bool can_show_light = 8; - optional string group_key = 9; + optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ]; optional int32 importance = 10; } message ListenersDisablingEffectsProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional int32 hint = 1; repeated ManagedServiceInfoProto listeners = 2; } message ManagedServiceInfoProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional android.content.ComponentNameProto component = 1; optional int32 user_id = 2; optional string service = 3; @@ -77,10 +86,14 @@ message ManagedServiceInfoProto { } message ManagedServicesProto { - optional string caption = 1; + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string caption = 1 [ (.android.privacy).dest = DEST_EXPLICIT ]; message ServiceProto { - repeated string name = 1; + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated string name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ]; optional int32 user_id = 2; optional bool is_primary = 3; } @@ -97,9 +110,13 @@ message ManagedServicesProto { } message RankingHelperProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + repeated string notification_signal_extractors = 1; message RecordProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional string package = 1; // Default value is UNKNOWN_UID = USER_NULL = -10000. optional int32 uid = 2; @@ -118,16 +135,72 @@ message RankingHelperProto { repeated RecordProto records_restored_without_uid = 3; } -message ZenModeProto { - enum ZenMode { - ZEN_MODE_OFF = 0; - ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; - ZEN_MODE_NO_INTERRUPTIONS = 2; - ZEN_MODE_ALARMS = 3; +enum ZenMode { + ZEN_MODE_OFF = 0; + ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; + ZEN_MODE_NO_INTERRUPTIONS = 2; + ZEN_MODE_ALARMS = 3; +} + +// An android.service.notification.Condition object. +message ConditionProto { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + optional string id = 1; + optional string summary = 2; + optional string line_1 = 3; + optional string line_2 = 4; + optional int32 icon = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; + + enum State { + // Indicates that Do Not Disturb should be turned off. + STATE_FALSE = 0; + // Indicates that Do Not Disturb should be turned on. + STATE_TRUE = 1; + STATE_UNKNOWN = 2; + STATE_ERROR = 3; } + optional State state = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; + + optional int32 flags = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; +} + +// An android.service.notification.ZenModeConfig.ZenRule object. +message ZenRuleProto { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + // Required for automatic (unique). + optional string id = 1; + // Required for automatic. + optional string name = 2; + // Required for automatic. + optional int64 creation_time_ms = 3 [ + (android.privacy).dest = DEST_AUTOMATIC + ]; + optional bool enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Package name, only used for manual rules. + optional string enabler = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // User manually disabled this instance. + optional bool is_snoozing = 6 [ + (android.privacy).dest = DEST_AUTOMATIC + ]; + optional ZenMode zen_mode = 7 [ + (android.privacy).dest = DEST_AUTOMATIC + ]; + + // Required for automatic. + optional string condition_id = 8; + optional ConditionProto condition = 9; + optional android.content.ComponentNameProto component = 10; +} + +// A dump from com.android.server.notification.ZenModeHelper. +message ZenModeProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional ZenMode zen_mode = 1; - repeated string enabled_active_conditions = 2; + repeated ZenRuleProto enabled_active_conditions = 2; optional int32 suppressed_effects = 3; - repeated string suppressors = 4; + repeated android.content.ComponentNameProto suppressors = 4; optional android.app.PolicyProto policy = 5; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b23a64b9f38f..2779cd6846d4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3967,6 +3967,7 @@ android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert" android:excludeFromRecents="true" android:process=":ui" + android:label="@string/harmful_app_warning_title" android:exported="false"> </activity> diff --git a/core/res/res/drawable/red_shield.xml b/core/res/res/drawable/red_shield.xml new file mode 100644 index 000000000000..7f425c78c708 --- /dev/null +++ b/core/res/res/drawable/red_shield.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="34dp" + android:height="37dp" + android:viewportWidth="34" + android:viewportHeight="37"> + + <group + android:translateX="-3.000000" + android:translateY="-2.000000"> + <path + android:fillType="evenOdd" + android:strokeWidth="1" + android:pathData="M 0 0 H 40 V 40 H 0 V 0 Z" /> + <path + android:fillColor="#D0021B" + android:fillType="evenOdd" + android:strokeWidth="1" + android:pathData="M35.5858891,6.865 C27.841629,3.02166667 19.6666667,2 19.6666667,2 C19.6666667,2 +11.4917044,3.02166667 3.74744428,6.865 C3.25808614,8.915 3,11.0533333 +3,13.2533333 C3,15.515 3.27484498,17.715 3.79269315,19.8216667 +C4.89374895,24.3033333 7.09753645,28.355 10.1023965,31.6783333 +C12.7385621,34.5983333 15.9964806,36.955 19.6666667,38.5433333 +C23.3368527,36.955 26.5947712,34.5983333 29.2326127,31.6783333 +C32.2357969,28.355 34.4395844,24.3033333 35.5423161,19.8216667 +C36.0584884,17.715 36.3333333,15.515 36.3333333,13.2533333 +C36.3333333,11.0533333 36.0769231,8.915 35.5858891,6.865 M21.3333333,27.8333333 +L18,27.8333333 L18,24.5 L21.3333333,24.5 L21.3333333,27.8333333 +L21.3333333,27.8333333 Z M21.3333333,22 L18,22 L18,12 L21.3333333,12 +L21.3333333,22 L21.3333333,22 Z" /> + </group> +</vector>
\ No newline at end of file diff --git a/core/res/res/layout/harmful_app_warning_dialog.xml b/core/res/res/layout/harmful_app_warning_dialog.xml new file mode 100644 index 000000000000..d41691f4bb1b --- /dev/null +++ b/core/res/res/layout/harmful_app_warning_dialog.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2018, 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 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. + */ +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/harmful_app_padding_top" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/harmful_app_name_padding_bottom" + android:paddingLeft="@dimen/harmful_app_name_padding_left" + android:paddingRight="@dimen/harmful_app_name_padding_right" + android:paddingTop="@dimen/harmful_app_name_padding_top" + android:orientation="horizontal"> + + <ImageView + android:layout_width="@dimen/harmful_app_icon_size" + android:layout_height="@dimen/harmful_app_icon_size" + android:scaleType="fitCenter" + android:src="@drawable/red_shield"/> + + <TextView + android:id="@+id/app_name_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:textColor="@color/primary_text_material_light" + android:textSize="@dimen/text_size_subhead_material" + android:paddingLeft="@dimen/harmful_app_icon_name_padding"> + </TextView> + </LinearLayout> + + <TextView + android:id="@+id/message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/harmful_app_message_padding_left" + android:paddingRight="@dimen/harmful_app_message_padding_right" + android:paddingBottom="@dimen/harmful_app_message_padding_bottom" + android:lineSpacingMultiplier="@dimen/harmful_app_message_line_spacing_modifier" + android:textSize="@dimen/text_size_body_1_material"/> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2c824ea01be7..e57b8b242490 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -33,6 +33,10 @@ <dimen name="toast_y_offset">24dp</dimen> <!-- Height of the status bar --> <dimen name="status_bar_height">24dp</dimen> + <!-- Height of area above QQS where battery/time go --> + <dimen name="quick_qs_offset_height">48dp</dimen> + <!-- Total height of QQS (quick_qs_offset_height + 128) --> + <dimen name="quick_qs_total_height">176dp</dimen> <!-- Height of the bottom navigation / system bar. --> <dimen name="navigation_bar_height">48dp</dimen> <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height --> @@ -635,4 +639,26 @@ <!-- Size of thumbnail used in the cross profile apps animation --> <dimen name="cross_profile_apps_thumbnail_size">72dp</dimen> + <!-- Padding between the title and content in the harmful app dialog --> + <dimen name="harmful_app_padding_top">10dp</dimen> + <!-- Bottom padding for the "app name" section of the harmful app dialog --> + <dimen name="harmful_app_name_padding_bottom">20dp</dimen> + <!-- Left padding for the "app name" section of the harmful app dialog --> + <dimen name="harmful_app_name_padding_left">24dp</dimen> + <!-- Right padding for the "app name" section of the harmful app dialog --> + <dimen name="harmful_app_name_padding_right">24dp</dimen> + <!-- Top padding for the "app name" section of the harmful app dialog --> + <dimen name="harmful_app_name_padding_top">8dp</dimen> + <!-- Padding between the icon and app name in the harmful app dialog --> + <dimen name="harmful_app_icon_name_padding">20dp</dimen> + <!-- The size of the icon on the harmful app dialog --> + <dimen name="harmful_app_icon_size">44dp</dimen> + <!-- Left padding for the message section of the harmful app dialog --> + <dimen name="harmful_app_message_padding_left">24dp</dimen> + <!-- Right padding for the message section of the harmful app dialog --> + <dimen name="harmful_app_message_padding_right">24dp</dimen> + <!-- Bottom padding for the message section of the harmful app dialog --> + <dimen name="harmful_app_message_padding_bottom">24dp</dimen> + <!-- Line spacing modifier for the message field of the harmful app dialog --> + <item name="harmful_app_message_line_spacing_modifier" type="dimen">1.22</item> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 549f9ad78423..3cde765e04cb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4842,12 +4842,12 @@ <!--Battery saver warning. STOPSHIP: Remove it eventually. --> <string name="battery_saver_warning_title" translatable="false">Extreme battery saver</string> - <!-- Label for the uninstall button on the harmful app warning dialog. --> - <string name="harmful_app_warning_uninstall">Uninstall</string> - <!-- Label for the launch anyway button on the harmful app warning dialog. --> - <string name="harmful_app_warning_launch_anyway">Launch anyway</string> - <!-- Title for the harmful app warning dialog. --> - <string name="harmful_app_warning_title">Uninstall harmful app?</string> + <!-- Label for the uninstall button on the harmful app warning dialog. [CHAR LIMIT=20] --> + <string name="harmful_app_warning_uninstall">UNINSTALL</string> + <!-- Label for the open anyway button on the harmful app warning dialog. [CHAR LIMIT=20] --> + <string name="harmful_app_warning_open_anyway">OPEN ANYWAY</string> + <!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] --> + <string name="harmful_app_warning_title">Harmful app detected</string> <!-- Text describing a permission request for one app to show another app's slices [CHAR LIMIT=NONE] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 710bbfbb1b14..9442d15dfff2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1636,6 +1636,7 @@ <java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" /> <java-symbol type="dimen" name="navigation_bar_width_car_mode" /> <java-symbol type="dimen" name="status_bar_height" /> + <java-symbol type="dimen" name="quick_qs_total_height" /> <java-symbol type="drawable" name="ic_jog_dial_sound_off" /> <java-symbol type="drawable" name="ic_jog_dial_sound_on" /> <java-symbol type="drawable" name="ic_jog_dial_unlock" /> @@ -3228,8 +3229,9 @@ <java-symbol type="string" name="shortcut_disabled_reason_unknown" /> <java-symbol type="string" name="harmful_app_warning_uninstall" /> - <java-symbol type="string" name="harmful_app_warning_launch_anyway" /> + <java-symbol type="string" name="harmful_app_warning_open_anyway" /> <java-symbol type="string" name="harmful_app_warning_title" /> + <java-symbol type="layout" name="harmful_app_warning_dialog" /> <java-symbol type="string" name="config_defaultAssistantAccessPackage" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2f747ec30ef9..733f7a107fa8 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -377,6 +377,7 @@ public class SettingsBackupTest { Settings.Global.TETHER_SUPPORTED, Settings.Global.TEXT_CLASSIFIER_CONSTANTS, Settings.Global.THEATER_MODE_ON, + Settings.Global.TIME_ONLY_MODE_ENABLED, Settings.Global.TRANSITION_ANIMATION_SCALE, Settings.Global.TRUSTED_SOUND, Settings.Global.TZINFO_UPDATE_CONTENT_URL, diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java index 4d34721b5aba..ce3ffb9e58ab 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -772,7 +772,8 @@ public class BstatsCpuTimesValidationTest { latch.countDown(); } }); - launchIntent.putExtras(extras); + launchIntent.putExtras(extras) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); sContext.startActivity(launchIntent); if (latch.await(START_ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { if (binders[0] == null) { diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 77df02bc5753..c926e1ff48a7 100644 --- a/packages/SettingsLib/res/values/arrays.xml +++ b/packages/SettingsLib/res/values/arrays.xml @@ -468,18 +468,6 @@ <item>show_deuteranomaly</item> </string-array> - <!-- Titles for debug renderer preference. [CHAR LIMIT=50] --> - <string-array name="debug_hw_renderer_entries"> - <item>OpenGL (Default)</item> - <item>OpenGL (Skia)</item> - </string-array> - - <!-- Values for debug renderer preference. --> - <string-array name="debug_hw_renderer_values" translatable="false" > - <item>opengl</item> - <item>skiagl</item> - </string-array> - <!-- Titles for app process limit preference. [CHAR LIMIT=35] --> <string-array name="app_process_limit_entries"> <item>Standard limit</item> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 4156653c493a..486a9bbed1f2 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -679,9 +679,6 @@ <!-- UI debug setting: show the amount of overdraw in apps using the GPU [CHAR LIMIT=25] --> <string name="debug_hw_overdraw">Debug GPU overdraw</string> - <!-- UI debug setting: select the renderer to use by RenderThread [CHAR LIMIT=25] --> - <string name="debug_hw_renderer">Set GPU Renderer</string> - <!-- UI debug setting: disable use of overlays? [CHAR LIMIT=25] --> <string name="disable_overlays">Disable HW overlays</string> <!-- UI debug setting: disable use of overlays summary [CHAR LIMIT=50] --> diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java new file mode 100644 index 000000000000..f740f7c01ce1 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java @@ -0,0 +1,174 @@ +/* + * 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.settingslib.suggestions; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.service.settings.suggestions.ISuggestionService; +import android.service.settings.suggestions.Suggestion; +import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; +import android.util.Log; + +import java.util.List; + +/** + * A controller class to access suggestion data. + */ +public class SuggestionController { + + /** + * Callback interface when service is connected/disconnected. + */ + public interface ServiceConnectionListener { + /** + * Called when service is connected. + */ + void onServiceConnected(); + + /** + * Called when service is disconnected. + */ + void onServiceDisconnected(); + } + + private static final String TAG = "SuggestionController"; + private static final boolean DEBUG = false; + + private final Context mContext; + private final Intent mServiceIntent; + + private ServiceConnection mServiceConnection; + private ISuggestionService mRemoteService; + private ServiceConnectionListener mConnectionListener; + + /** + * Create a new controller instance. + * + * @param context caller context + * @param service The component name for service. + * @param listener listener to receive service connected/disconnected event. + */ + public SuggestionController(Context context, ComponentName service, + ServiceConnectionListener listener) { + mContext = context.getApplicationContext(); + mConnectionListener = listener; + mServiceIntent = new Intent().setComponent(service); + mServiceConnection = createServiceConnection(); + } + + /** + * Start the controller. + */ + public void start() { + mContext.bindServiceAsUser(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE, + android.os.Process.myUserHandle()); + } + + /** + * Stop the controller. + */ + public void stop() { + if (mRemoteService != null) { + mRemoteService = null; + mContext.unbindService(mServiceConnection); + } + } + + /** + * Get setting suggestions. + */ + @Nullable + @WorkerThread + public List<Suggestion> getSuggestions() { + if (!isReady()) { + return null; + } + try { + return mRemoteService.getSuggestions(); + } catch (NullPointerException e) { + Log.w(TAG, "mRemote service detached before able to query", e); + return null; + } catch (RemoteException e) { + Log.w(TAG, "Error when calling getSuggestion()", e); + return null; + } + } + + public void dismissSuggestions(Suggestion suggestion) { + if (!isReady()) { + Log.w(TAG, "SuggestionController not ready, cannot dismiss " + suggestion.getId()); + return; + } + try { + mRemoteService.dismissSuggestion(suggestion); + } catch (RemoteException e) { + Log.w(TAG, "Error when calling dismissSuggestion()", e); + } + } + + public void launchSuggestion(Suggestion suggestion) { + if (!isReady()) { + Log.w(TAG, "SuggestionController not ready, cannot launch " + suggestion.getId()); + return; + } + + try { + mRemoteService.launchSuggestion(suggestion); + } catch (RemoteException e) { + Log.w(TAG, "Error when calling launchSuggestion()", e); + } + } + + /** + * Whether or not the manager is ready + */ + private boolean isReady() { + return mRemoteService != null; + } + + /** + * Create a new {@link ServiceConnection} object to handle service connect/disconnect event. + */ + private ServiceConnection createServiceConnection() { + return new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) { + Log.d(TAG, "Service is connected"); + } + mRemoteService = ISuggestionService.Stub.asInterface(service); + if (mConnectionListener != null) { + mConnectionListener.onServiceConnected(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (mConnectionListener != null) { + mRemoteService = null; + mConnectionListener.onServiceDisconnected(); + } + } + }; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java new file mode 100644 index 000000000000..46fc32fa43cc --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java @@ -0,0 +1,140 @@ +/* + * 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.settingslib.suggestions; + +import android.app.LoaderManager; +import android.arch.lifecycle.OnLifecycleEvent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Loader; +import android.os.Bundle; +import android.service.settings.suggestions.Suggestion; +import android.support.annotation.Nullable; +import android.util.Log; + +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.List; + +/** + * Manages IPC communication to SettingsIntelligence for suggestion related services. + */ +public class SuggestionControllerMixin implements SuggestionController.ServiceConnectionListener, + android.arch.lifecycle.LifecycleObserver, LoaderManager.LoaderCallbacks<List<Suggestion>> { + + public interface SuggestionControllerHost { + /** + * Called when suggestion data fetching is ready. + */ + void onSuggestionReady(List<Suggestion> data); + + /** + * Returns {@link LoaderManager} associated with the host. If host is not attached to + * activity then return null. + */ + @Nullable + LoaderManager getLoaderManager(); + } + + private static final String TAG = "SuggestionCtrlMixin"; + private static final boolean DEBUG = false; + + private final Context mContext; + private final SuggestionController mSuggestionController; + private final SuggestionControllerHost mHost; + + private boolean mSuggestionLoaded; + + public SuggestionControllerMixin(Context context, SuggestionControllerHost host, + Lifecycle lifecycle, ComponentName componentName) { + mContext = context.getApplicationContext(); + mHost = host; + mSuggestionController = new SuggestionController(mContext, componentName, + this /* serviceConnectionListener */); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + if (DEBUG) { + Log.d(TAG, "SuggestionController started"); + } + mSuggestionController.start(); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + if (DEBUG) { + Log.d(TAG, "SuggestionController stopped."); + } + mSuggestionController.stop(); + } + + @Override + public void onServiceConnected() { + final LoaderManager loaderManager = mHost.getLoaderManager(); + if (loaderManager != null) { + loaderManager.restartLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS, + null /* args */, this /* callback */); + } + } + + @Override + public void onServiceDisconnected() { + if (DEBUG) { + Log.d(TAG, "SuggestionService disconnected"); + } + final LoaderManager loaderManager = mHost.getLoaderManager(); + if (loaderManager != null) { + loaderManager.destroyLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS); + } + } + + @Override + public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) { + if (id == SuggestionLoader.LOADER_ID_SUGGESTIONS) { + mSuggestionLoaded = false; + return new SuggestionLoader(mContext, mSuggestionController); + } + throw new IllegalArgumentException("This loader id is not supported " + id); + } + + @Override + public void onLoadFinished(Loader<List<Suggestion>> loader, List<Suggestion> data) { + mSuggestionLoaded = true; + mHost.onSuggestionReady(data); + } + + @Override + public void onLoaderReset(Loader<List<Suggestion>> loader) { + mSuggestionLoaded = false; + } + + public boolean isSuggestionLoaded() { + return mSuggestionLoaded; + } + + public void dismissSuggestion(Suggestion suggestion) { + mSuggestionController.dismissSuggestions(suggestion); + } + + public void launchSuggestion(Suggestion suggestion) { + mSuggestionController.launchSuggestion(suggestion); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java new file mode 100644 index 000000000000..9c1af1edc778 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java @@ -0,0 +1,54 @@ +/* + * 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.settingslib.suggestions; + +import android.content.Context; +import android.service.settings.suggestions.Suggestion; +import android.util.Log; + +import com.android.settingslib.utils.AsyncLoader; + +import java.util.List; + +public class SuggestionLoader extends AsyncLoader<List<Suggestion>> { + + public static final int LOADER_ID_SUGGESTIONS = 42; + private static final String TAG = "SuggestionLoader"; + + private final SuggestionController mSuggestionController; + + public SuggestionLoader(Context context, SuggestionController controller) { + super(context); + mSuggestionController = controller; + } + + @Override + protected void onDiscardResult(List<Suggestion> result) { + + } + + @Override + public List<Suggestion> loadInBackground() { + final List<Suggestion> data = mSuggestionController.getSuggestions(); + if (data == null) { + Log.d(TAG, "data is null"); + } else { + Log.d(TAG, "data size " + data.size()); + } + return data; + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/ShadowSuggestionController.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/ShadowSuggestionController.java new file mode 100644 index 000000000000..61bc83b8f72e --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/ShadowSuggestionController.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.settingslib.suggestions; + +import android.service.settings.suggestions.Suggestion; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.List; + +@Implements(SuggestionController.class) +public class ShadowSuggestionController { + + public static boolean sStartCalled; + public static boolean sStopCalled; + public static boolean sGetSuggestionCalled; + + public static List<Suggestion> sSuggestions; + + public static void reset() { + sStartCalled = false; + sStopCalled = false; + sGetSuggestionCalled = false; + sSuggestions = null; + } + + @Implementation + public void start() { + sStartCalled = true; + } + + @Implementation + public void stop() { + sStopCalled = true; + } + + public static void setSuggestion(List<Suggestion> suggestions) { + sSuggestions = suggestions; + } + + @Implementation + public List<Suggestion> getSuggestions() { + sGetSuggestionCalled = true; + return sSuggestions; + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java new file mode 100644 index 000000000000..ed1c405f8a81 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java @@ -0,0 +1,132 @@ +/* + * 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.settingslib.suggestions; + +import static android.arch.lifecycle.Lifecycle.Event.ON_START; +import static android.arch.lifecycle.Lifecycle.Event.ON_STOP; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.LoaderManager; +import android.arch.lifecycle.LifecycleOwner; +import android.content.ComponentName; +import android.content.Context; + +import com.android.settingslib.TestConfig; +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsLibRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, + shadows = { + ShadowSuggestionController.class + }) +public class SuggestionControllerMixinTest { + + @Mock + private SuggestionControllerMixin.SuggestionControllerHost mHost; + + private Context mContext; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + private SuggestionControllerMixin mMixin; + private ComponentName mComponentName; + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + mComponentName = new ComponentName( + "com.android.settings.intelligence", + "com.android.settings.intelligence.suggestions.SuggestionService"); + } + + @After + public void tearDown() { + ShadowSuggestionController.reset(); + } + + @Test + public void goThroughLifecycle_onStartStop_shouldStartStopController() { + mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle, mComponentName); + + mLifecycle.handleLifecycleEvent(ON_START); + assertThat(ShadowSuggestionController.sStartCalled).isTrue(); + + mLifecycle.handleLifecycleEvent(ON_STOP); + assertThat(ShadowSuggestionController.sStopCalled).isTrue(); + } + + @Test + public void onServiceConnected_shouldGetSuggestion() { + final LoaderManager loaderManager = mock(LoaderManager.class); + when(mHost.getLoaderManager()).thenReturn(loaderManager); + + mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceConnected(); + + verify(loaderManager).restartLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS, + null /* args */, mMixin /* callback */); + } + + @Test + public void onServiceConnected_hostNotAttached_shouldDoNothing() { + when(mHost.getLoaderManager()).thenReturn(null); + + mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceConnected(); + + verify(mHost).getLoaderManager(); + } + + @Test + public void onServiceDisconnected_hostNotAttached_shouldDoNothing() { + when(mHost.getLoaderManager()).thenReturn(null); + + mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceDisconnected(); + + verify(mHost).getLoaderManager(); + } + + @Test + public void doneLoadingg_shouldSetSuggestionLoaded() { + mMixin = new SuggestionControllerMixin(mContext, mHost, mLifecycle, mComponentName); + + mMixin.onLoadFinished(mock(SuggestionLoader.class), null); + + assertThat(mMixin.isSuggestionLoaded()).isTrue(); + + mMixin.onLoaderReset(mock(SuggestionLoader.class)); + + assertThat(mMixin.isSuggestionLoaded()).isFalse(); + } +} diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 7b30d6ae8717..cd1be152b8d2 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -40,7 +40,7 @@ <LinearLayout android:id="@+id/system_icons_super_container" android:layout_width="wrap_content" - android:layout_height="@dimen/status_bar_header_height" + android:layout_height="@*android:dimen/quick_qs_total_height" android:layout_toStartOf="@id/multi_user_switch" android:layout_alignWithParentIfMissing="true" android:layout_marginStart="@dimen/system_icons_super_container_margin_start" diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 5bcb7fd2685e..1dab76183864 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -33,7 +33,7 @@ <View android:id="@+id/quick_settings_status_bar_background" android:layout_width="match_parent" - android:layout_height="@dimen/qs_header_system_icons_area_height" + android:layout_height="@*android:dimen/quick_qs_offset_height" android:clipToPadding="false" android:clipChildren="false" android:background="#ff000000" /> @@ -43,7 +43,7 @@ android:id="@+id/quick_settings_gradient_view" android:layout_width="match_parent" android:layout_height="126dp" - android:layout_marginTop="@dimen/qs_header_system_icons_area_height" + android:layout_marginTop="@*android:dimen/quick_qs_offset_height" android:clipToPadding="false" android:clipChildren="false" android:background="@drawable/qs_bg_gradient" /> @@ -51,7 +51,7 @@ <com.android.systemui.qs.QSPanel android:id="@+id/quick_settings_panel" - android:layout_marginTop="@dimen/qs_header_system_icons_area_height" + android:layout_marginTop="@*android:dimen/quick_qs_offset_height" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="48dp" diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index dacc3f96220b..cc79d0d9b7dd 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -20,7 +20,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/header" android:layout_width="match_parent" - android:layout_height="@dimen/status_bar_header_height" + android:layout_height="@*android:dimen/quick_qs_total_height" android:layout_gravity="@integer/notification_panel_layout_gravity" android:baselineAligned="false" android:clickable="false" diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index 2c69501106a6..f38129f0dffa 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -19,7 +19,7 @@ xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/quick_status_bar_system_icons" android:layout_width="match_parent" - android:layout_height="@dimen/qs_header_system_icons_area_height" + android:layout_height="@*android:dimen/quick_qs_offset_height" android:layout_alignParentEnd="true" android:clipChildren="false" android:clipToPadding="false" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d58c725c6462..3db79d7556d5 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -214,9 +214,6 @@ <!-- Amount of close_handle that will NOT overlap the notification list --> <dimen name="close_handle_underlap">32dp</dimen> - <!-- Height of the status bar header bar --> - <dimen name="status_bar_header_height">178dp</dimen> - <!-- Height of the status bar header bar in the car setting. --> <dimen name="car_status_bar_header_height">128dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 6d61a0c198f9..9b6af43a1920 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -771,8 +771,10 @@ <string name="quick_settings_tethering_label">Tethering</string> <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] --> <string name="quick_settings_hotspot_label">Hotspot</string> + <!-- QuickSettings: Hotspot. Secondary label shown when the hotspot is being enabled [CHAR LIMIT=NONE] --> + <string name="quick_settings_hotspot_secondary_label_transient">Turning on...</string> <!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] --> - <plurals name="quick_settings_hotspot_num_devices"> + <plurals name="quick_settings_hotspot_secondary_label_num_devices"> <item quantity="one">%d device</item> <item quantity="other">%d devices</item> </plurals> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 17ede6586402..77768b1a4bd1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -166,7 +166,8 @@ public class QuickStatusBarHeader extends RelativeLayout if (disabled == mQsDisabled) return; mQsDisabled = disabled; mHeaderQsPanel.setDisabledByPolicy(disabled); - final int rawHeight = (int) getResources().getDimension(R.dimen.status_bar_header_height); + final int rawHeight = (int) getResources().getDimension( + com.android.internal.R.dimen.quick_qs_total_height); getLayoutParams().height = disabled ? (rawHeight - mHeaderQsPanel.getHeight()) : rawHeight; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index e1b58fe4c2d6..080e320802e6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -113,11 +113,11 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { if (state.slash == null) { state.slash = new SlashState(); } - state.label = mContext.getString(R.string.quick_settings_hotspot_label); - - checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING); final int numConnectedDevices; + final boolean isTransient = mController.isHotspotTransient(); + + checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING); if (arg instanceof CallbackInfo) { CallbackInfo info = (CallbackInfo) arg; state.value = info.enabled; @@ -127,11 +127,11 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { numConnectedDevices = mController.getNumConnectedDevices(); } - state.secondaryLabel = getSecondaryLabel(state.value, numConnectedDevices); - state.icon = mEnabledStatic; + state.label = mContext.getString(R.string.quick_settings_hotspot_label); + state.secondaryLabel = getSecondaryLabel(state.value, isTransient, numConnectedDevices); state.isAirplaneMode = mAirplaneMode.getValue() != 0; - state.isTransient = mController.isHotspotTransient(); + state.isTransient = isTransient; state.slash.isSlashed = !state.value && !state.isTransient; if (state.isTransient) { state.icon = ResourceIcon.get(R.drawable.ic_hotspot_transient_animation); @@ -143,10 +143,13 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { } @Nullable - private String getSecondaryLabel(boolean enabled, int numConnectedDevices) { - if (numConnectedDevices > 0 && enabled) { + private String getSecondaryLabel( + boolean enabled, boolean isTransient, int numConnectedDevices) { + if (isTransient) { + return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient); + } else if (numConnectedDevices > 0 && enabled) { return mContext.getResources().getQuantityString( - R.plurals.quick_settings_hotspot_num_devices, + R.plurals.quick_settings_hotspot_secondary_label_num_devices, numConnectedDevices, numConnectedDevices); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index da809c12d16c..09acf3e4b53b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -115,7 +115,7 @@ public class KeyguardStatusBarView extends RelativeLayout lp = (MarginLayoutParams) mSystemIconsSuperContainer.getLayoutParams(); lp.height = getResources().getDimensionPixelSize( - R.dimen.status_bar_header_height); + com.android.internal.R.dimen.quick_qs_total_height); lp.setMarginStart(getResources().getDimensionPixelSize( R.dimen.system_icons_super_container_margin_start)); mSystemIconsSuperContainer.setLayoutParams(lp); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index 0954fd054e2d..0d36efda9ece 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -308,8 +308,13 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onTouchEvent(MotionEvent event) { + // The same down event was just sent on intercept and therefore can be ignored here + boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN + && mOverviewEventSender.getProxy() != null; boolean result = mStatusBar.isPresenterFullyCollapsed() - && (mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event)); + && (mQuickScrubController.onTouchEvent(event) + || ignoreProxyDownEvent + || proxyMotionEvents(event)); if (mDockWindowEnabled) { result |= handleDockWindowEvent(event); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 56b7201ea274..3e13ddb1028a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -341,7 +341,8 @@ public class VolumeDialogImpl implements VolumeDialog { row.connectedDevice = row.view.findViewById(R.id.volume_row_connected_device); // forward events above the slider into the slider - row.view.setOnTouchListener(new OnTouchListener() { + row.view.findViewById(R.id.volume_row_slider_frame) + .setOnTouchListener(new OnTouchListener() { private final Rect mSliderHitRect = new Rect(); private boolean mDragging; diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java index e9703670008d..dc2707b6ff8b 100644..100755 --- a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java +++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java @@ -22,11 +22,15 @@ import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase; +import android.os.Build; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; import android.util.Log; @@ -216,7 +220,27 @@ public class WapPushManager extends Service { intent.setClassName(mContext, lastapp.className); intent.setComponent(new ComponentName(lastapp.packageName, lastapp.className)); - if (mContext.startService(intent) == null) { + PackageManager pm = mContext.getPackageManager(); + PowerManager powerManager = + (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + try { + ApplicationInfo appInfo = pm.getApplicationInfo(lastapp.packageName, 0); + if (appInfo.targetSdkVersion < Build.VERSION_CODES.O || + powerManager.isIgnoringBatteryOptimizations(lastapp.packageName)) { + if (mContext.startService(intent) == null) { + Log.w(LOG_TAG, "invalid name " + + lastapp.packageName + "/" + lastapp.className); + return WapPushManagerParams.INVALID_RECEIVER_NAME; + } + } else { + if (mContext.startForegroundService(intent) == null) { + Log.w(LOG_TAG, "invalid name " + + lastapp.packageName + "/" + lastapp.className); + return WapPushManagerParams.INVALID_RECEIVER_NAME; + } + } + + } catch (NameNotFoundException e) { Log.w(LOG_TAG, "invalid name " + lastapp.packageName + "/" + lastapp.className); return WapPushManagerParams.INVALID_RECEIVER_NAME; diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml index 43bde88dabdd..a584a7f3fb90 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml @@ -47,6 +47,10 @@ <!-- Height of the status bar --> <dimen name="status_bar_height">48dp</dimen> + <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> + <dimen name="quick_qs_offset_height">48dp</dimen> + <!-- Total height of QQS (quick_qs_offset_height + 128) --> + <dimen name="quick_qs_total_height">176dp</dimen> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml index 9cf48d9e15a8..915e16412155 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml @@ -47,6 +47,10 @@ <!-- Height of the status bar --> <dimen name="status_bar_height">48dp</dimen> + <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> + <dimen name="quick_qs_offset_height">48dp</dimen> + <!-- Total height of QQS (quick_qs_offset_height + 128) --> + <dimen name="quick_qs_total_height">176dp</dimen> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml index 1ce41f07691d..b8e29da8c8e7 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml @@ -47,6 +47,10 @@ <!-- Height of the status bar --> <dimen name="status_bar_height">48dp</dimen> + <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> + <dimen name="quick_qs_offset_height">48dp</dimen> + <!-- Total height of QQS (quick_qs_offset_height + 128) --> + <dimen name="quick_qs_total_height">176dp</dimen> </resources> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f658b276d3ab..520fdceead7c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -87,6 +87,7 @@ import static android.os.Process.ROOT_UID; import static android.os.Process.SCHED_FIFO; import static android.os.Process.SCHED_OTHER; import static android.os.Process.SCHED_RESET_ON_FORK; +import static android.os.Process.SE_UID; import static android.os.Process.SHELL_UID; import static android.os.Process.SIGNAL_QUIT; import static android.os.Process.SIGNAL_USR1; @@ -20725,6 +20726,7 @@ public class ActivityManagerService extends IActivityManager.Stub case PHONE_UID: case BLUETOOTH_UID: case NFC_UID: + case SE_UID: isCallerSystem = true; break; default: diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java index 569e9ec995d7..08607bc8ef2c 100644 --- a/services/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java @@ -64,6 +64,14 @@ public interface JobSchedulerInternal { void removeBackingUpUid(int uid); void clearAllBackingUpUids(); + /** + * The user has started interacting with the app. Take any appropriate action. + */ + void reportAppUsage(String packageName, int userId); + + /** + * Report a snapshot of sync-related jobs back to the sync manager + */ JobStorePersistStats getPersistStats(); /** diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 2066f2af46dd..8fa331880abc 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1071,6 +1071,11 @@ public final class JobSchedulerService extends com.android.server.SystemService } } + void reportAppUsage(String packageName, int userId) { + // This app just transitioned into interactive use or near equivalent, so we should + // take a look at its job state for feedback purposes. + } + /** * Initializes the system service. * <p> @@ -1809,7 +1814,9 @@ public final class JobSchedulerService extends com.android.server.SystemService // If the app is in a non-active standby bucket, make sure we've waited // an appropriate amount of time since the last invocation. During device- // wide parole, standby bucketing is ignored. - if (!mInParole) { + // + // But if a job has FLAG_EXEMPT_FROM_APP_STANDBY, don't check it. + if (!mInParole && !job.getJob().isExemptedFromAppStandby()) { final int bucket = job.getStandbyBucket(); if (mHeartbeat < mNextBucketHeartbeat[bucket]) { // Only skip this job if it's still waiting for the end of its (initial) nominal @@ -2151,6 +2158,11 @@ public final class JobSchedulerService extends com.android.server.SystemService } @Override + public void reportAppUsage(String packageName, int userId) { + JobSchedulerService.this.reportAppUsage(packageName, userId); + } + + @Override public JobStorePersistStats getPersistStats() { synchronized (mLock) { return new JobStorePersistStats(mJobs.getPersistStats()); @@ -2212,6 +2224,40 @@ public final class JobSchedulerService extends com.android.server.SystemService } mInParole = isParoleOn; } + + @Override + public void onUserInteractionStarted(String packageName, int userId) { + final int uid = mLocalPM.getPackageUid(packageName, + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); + if (uid < 0) { + // Quietly ignore; the case is already logged elsewhere + return; + } + + final long sinceLast = sElapsedRealtimeClock.millis() - + mUsageStats.getTimeSinceLastJobRun(packageName, userId); + final DeferredJobCounter counter = new DeferredJobCounter(); + synchronized (mLock) { + mJobs.forEachJobForSourceUid(uid, counter); + } + + mUsageStats.reportAppJobState(packageName, userId, counter.numDeferred(), sinceLast); + } + } + + static class DeferredJobCounter implements JobStatusFunctor { + private int mDeferred = 0; + + public int numDeferred() { + return mDeferred; + } + + @Override + public void process(JobStatus job) { + if (job.getWhenStandbyDeferred() > 0) { + mDeferred++; + } + } } public static int standbyBucketToBucketIndex(int bucket) { @@ -2295,6 +2341,22 @@ public final class JobSchedulerService extends com.android.server.SystemService return canPersist; } + private void validateJobFlags(JobInfo job, int callingUid) { + if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG); + } + if ((job.getFlags() & JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY) != 0) { + if (callingUid != Process.SYSTEM_UID) { + throw new SecurityException("Job has invalid flags"); + } + if (job.hasLateConstraint() || job.hasEarlyConstraint()) { + Slog.wtf(TAG, "Jobs with time-constraints mustn't have" + +" FLAG_EXEMPT_FROM_APP_STANDBY. Job=" + job); + } + } + } + // IJobScheduler implementation @Override public int schedule(JobInfo job) throws RemoteException { @@ -2313,10 +2375,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } } - if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { - getContext().enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG); - } + validateJobFlags(job, uid); long ident = Binder.clearCallingIdentity(); try { @@ -2344,10 +2403,7 @@ public final class JobSchedulerService extends com.android.server.SystemService throw new NullPointerException("work is null"); } - if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { - getContext().enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG); - } + validateJobFlags(job, uid); long ident = Binder.clearCallingIdentity(); try { @@ -2378,10 +2434,7 @@ public final class JobSchedulerService extends com.android.server.SystemService + " not permitted to schedule jobs for other apps"); } - if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { - getContext().enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG); - } + validateJobFlags(job, callerUid); long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index f23147b445c2..37b39907e976 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -24,6 +24,7 @@ import android.app.job.IJobService; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobWorkItem; +import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -46,6 +47,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.job.controllers.JobStatus; /** @@ -238,6 +240,11 @@ public final class JobServiceContext implements ServiceConnection { } } + UsageStatsManagerInternal usageStats = + LocalServices.getService(UsageStatsManagerInternal.class); + usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(), + mExecutionStartTimeElapsed); + // Once we'e begun executing a job, we by definition no longer care whether // it was inflated from disk with not-yet-coherent delay/deadline bounds. job.clearPersistedUtcTimes(); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 31c20cbf82f9..28fa86b3a893 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1348,11 +1348,11 @@ public class LockSettingsService extends ILockSettings.Stub { .verifyChallenge(userId, 0, willStore.hash, credential.getBytes()); setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); - mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, - userId); // Refresh the auth token doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */); synchronizeUnifiedWorkChallengeForProfiles(userId, null); + mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, + userId); } else { throw new RemoteException("Failed to enroll " + (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password" @@ -1982,8 +1982,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public KeyChainSnapshot getRecoveryData(@NonNull byte[] account) throws RemoteException { - return mRecoverableKeyStoreManager.getRecoveryData(account); + public KeyChainSnapshot getKeyChainSnapshot() throws RemoteException { + return mRecoverableKeyStoreManager.getKeyChainSnapshot(); } public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent) @@ -2494,6 +2494,7 @@ public class LockSettingsService extends ILockSettings.Stub { (response != null ? "rate limit exceeded" : "failed")); return; } + mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId); } @Override diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index db46c3d4df3d..662ffc814390 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -72,7 +72,7 @@ public class KeySyncTask implements Runnable { private final int mCredentialType; private final String mCredential; private final boolean mCredentialUpdated; - private final PlatformKeyManager.Factory mPlatformKeyManagerFactory; + private final PlatformKeyManager mPlatformKeyManager; private final RecoverySnapshotStorage mRecoverySnapshotStorage; private final RecoverySnapshotListenersStorage mSnapshotListenersStorage; @@ -94,7 +94,7 @@ public class KeySyncTask implements Runnable { credentialType, credential, credentialUpdated, - () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb)); + PlatformKeyManager.getInstance(context, recoverableKeyStoreDb)); } /** @@ -105,9 +105,7 @@ public class KeySyncTask implements Runnable { * @param credentialType The type of credential as defined in {@code LockPatternUtils} * @param credential The credential, encoded as a {@link String}. * @param credentialUpdated signals weather credentials were updated. - * @param platformKeyManagerFactory Instantiates a {@link PlatformKeyManager} for the user. - * This is a factory to enable unit testing, as otherwise it would be impossible to test - * without a screen unlock occurring! + * @param platformKeyManager platform key manager */ @VisibleForTesting KeySyncTask( @@ -118,14 +116,14 @@ public class KeySyncTask implements Runnable { int credentialType, String credential, boolean credentialUpdated, - PlatformKeyManager.Factory platformKeyManagerFactory) { + PlatformKeyManager platformKeyManager) { mSnapshotListenersStorage = recoverySnapshotListenersStorage; mRecoverableKeyStoreDb = recoverableKeyStoreDb; mUserId = userId; mCredentialType = credentialType; mCredential = credential; mCredentialUpdated = credentialUpdated; - mPlatformKeyManagerFactory = platformKeyManagerFactory; + mPlatformKeyManager = platformKeyManager; mRecoverySnapshotStorage = snapshotStorage; } @@ -145,6 +143,8 @@ public class KeySyncTask implements Runnable { if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { // Application keys for the user will not be available for sync. Log.w(TAG, "Credentials are not set for user " + mUserId); + int generation = mPlatformKeyManager.getGenerationId(mUserId); + mPlatformKeyManager.invalidatePlatformKey(mUserId, generation); return; } @@ -158,9 +158,17 @@ public class KeySyncTask implements Runnable { } private void syncKeysForAgent(int recoveryAgentUid) { + boolean recreateCurrentVersion = false; if (!shoudCreateSnapshot(recoveryAgentUid)) { - Log.d(TAG, "Key sync not needed."); - return; + recreateCurrentVersion = + (mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid) != null) + && (mRecoverySnapshotStorage.get(recoveryAgentUid) == null); + if (recreateCurrentVersion) { + Log.d(TAG, "Recreating most recent snapshot"); + } else { + Log.d(TAG, "Key sync not needed."); + return; + } } if (!mSnapshotListenersStorage.hasListener(recoveryAgentUid)) { @@ -253,23 +261,21 @@ public class KeySyncTask implements Runnable { Log.e(TAG,"Could not encrypt with recovery key", e); return; } - // TODO: store raw data in RecoveryServiceMetadataEntry and generate Parcelables later - // TODO: use Builder. - KeyChainProtectionParams metadata = new KeyChainProtectionParams( - /*userSecretType=*/ TYPE_LOCKSCREEN, - /*lockScreenUiFormat=*/ getUiFormat(mCredentialType, mCredential), - /*keyDerivationParams=*/ KeyDerivationParams.createSha256Params(salt), - /*secret=*/ new byte[0]); + KeyChainProtectionParams metadata = new KeyChainProtectionParams.Builder() + .setUserSecretType(TYPE_LOCKSCREEN) + .setLockScreenUiFormat(getUiFormat(mCredentialType, mCredential)) + .setKeyDerivationParams(KeyDerivationParams.createSha256Params(salt)) + .setSecret(new byte[0]) + .build(); + ArrayList<KeyChainProtectionParams> metadataList = new ArrayList<>(); metadataList.add(metadata); - int snapshotVersion = incrementSnapshotVersion(recoveryAgentUid); - // If application keys are not updated, snapshot will not be created on next unlock. mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false); mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyChainSnapshot.Builder() - .setSnapshotVersion(snapshotVersion) + .setSnapshotVersion(getSnapshotVersion(recoveryAgentUid, recreateCurrentVersion)) .setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS) .setCounterId(counterId) .setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey)) @@ -283,9 +289,14 @@ public class KeySyncTask implements Runnable { } @VisibleForTesting - int incrementSnapshotVersion(int recoveryAgentUid) { + int getSnapshotVersion(int recoveryAgentUid, boolean recreateCurrentVersion) { Long snapshotVersion = mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid); - snapshotVersion = snapshotVersion == null ? 1 : snapshotVersion + 1; + if (recreateCurrentVersion) { + // version shouldn't be null at this moment. + snapshotVersion = snapshotVersion == null ? 1 : snapshotVersion; + } else { + snapshotVersion = snapshotVersion == null ? 1 : snapshotVersion + 1; + } mRecoverableKeyStoreDb.setSnapshotVersion(mUserId, recoveryAgentUid, snapshotVersion); return snapshotVersion.intValue(); @@ -304,8 +315,7 @@ public class KeySyncTask implements Runnable { throws InsecureUserException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException, InvalidKeyException, InvalidAlgorithmParameterException { - PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance(); - PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId);; + PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);; Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys( mUserId, recoveryAgentUid, decryptKey.getGenerationId()); return WrappedKey.unwrapKeys(decryptKey, wrappedKeys); @@ -414,10 +424,10 @@ public class KeySyncTask implements Runnable { Map<String, byte[]> encryptedApplicationKeys) { ArrayList<WrappedApplicationKey> keyEntries = new ArrayList<>(); for (String alias : encryptedApplicationKeys.keySet()) { - keyEntries.add( - new WrappedApplicationKey( - alias, - encryptedApplicationKeys.get(alias))); + keyEntries.add(new WrappedApplicationKey.Builder() + .setAlias(alias) + .setEncryptedKeyMaterial(encryptedApplicationKeys.get(alias)) + .build()); } return keyEntries; } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index ee6a89312988..3a78f950675e 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -129,6 +129,26 @@ public class PlatformKeyManager { } /** + * Removes the platform key from Android KeyStore. + * It is triggered when user disables lock screen. + * + * @param userId The ID of the user to whose lock screen the platform key must be bound. + * @param generationId Generation id. + * + * @hide + */ + public void invalidatePlatformKey(int userId, int generationId) { + if (generationId != -1) { + try { + mKeyStore.deleteEntry(getEncryptAlias(userId, generationId)); + mKeyStore.deleteEntry(getDecryptAlias(userId, generationId)); + } catch (KeyStoreException e) { + // Ignore failed attempt to delete key. + } + } + } + + /** * Generates a new key and increments the generation ID. Should be invoked if the platform key * is corrupted and needs to be rotated. * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}. @@ -152,6 +172,7 @@ public class PlatformKeyManager { if (generationId == -1) { nextId = 1; } else { + invalidatePlatformKey(userId, generationId); nextId = generationId + 1; } generateAndLoadKey(userId, nextId); @@ -197,8 +218,12 @@ public class PlatformKeyManager { private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); + String alias = getEncryptAlias(userId, generationId); + if (!mKeyStore.containsAlias(alias)) { + throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); + } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( - getEncryptAlias(userId, generationId), /*password=*/ null); + alias, /*password=*/ null); return new PlatformEncryptionKey(generationId, key); } @@ -242,8 +267,12 @@ public class PlatformKeyManager { private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { int generationId = getGenerationId(userId); + String alias = getDecryptAlias(userId, generationId); + if (!mKeyStore.containsAlias(alias)) { + throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias); + } AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( - getDecryptAlias(userId, generationId), /*password=*/ null); + alias, /*password=*/ null); return new PlatformDecryptionKey(generationId, key); } @@ -405,16 +434,4 @@ public class PlatformKeyManager { return keyStore; } - /** - * @hide - */ - public interface Factory { - /** - * New PlatformKeyManager instance. - * - * @hide - */ - PlatformKeyManager newInstance() - throws NoSuchAlgorithmException, InsecureUserException, KeyStoreException; - } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 0d567d1e971d..37117e3c2a0f 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -171,7 +171,7 @@ public class RecoverableKeyStoreManager { * @hide */ public @NonNull - KeyChainSnapshot getRecoveryData(@NonNull byte[] account) + KeyChainSnapshot getKeyChainSnapshot() throws RemoteException { checkRecoverKeyStorePermission(); int uid = Binder.getCallingUid(); @@ -579,6 +579,7 @@ public class RecoverableKeyStoreManager { /** * This function can only be used inside LockSettingsService. + * * @param storedHashType from {@code CredentialHash} * @param credential - unencrypted String * @param userId for the user whose lock screen credentials were changed. @@ -604,7 +605,7 @@ public class RecoverableKeyStoreManager { } catch (KeyStoreException e) { Log.e(TAG, "Key store error encountered during recoverable key sync", e); } catch (InsecureUserException e) { - Log.wtf(TAG, "Impossible - insecure user, but user just entered lock screen", e); + Log.e(TAG, "InsecureUserException during lock screen secret update", e); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4c9da8949cc9..5e3d77874e9b 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3421,7 +3421,7 @@ public class NotificationManagerService extends SystemService { long zenLog = proto.start(NotificationServiceDumpProto.ZEN); mZenModeHelper.dump(proto); for (ComponentName suppressor : mEffectsSuppressors) { - proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString()); + suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS); } proto.end(zenLog); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 932e4f948a82..2859613c0047 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -553,16 +553,15 @@ public class ZenModeHelper { } void dump(ProtoOutputStream proto) { - proto.write(ZenModeProto.ZEN_MODE, mZenMode); synchronized (mConfig) { if (mConfig.manualRule != null) { - proto.write(ZenModeProto.ENABLED_ACTIVE_CONDITIONS, mConfig.manualRule.toString()); + mConfig.manualRule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS); } for (ZenRule rule : mConfig.automaticRules.values()) { if (rule.enabled && rule.condition.state == Condition.STATE_TRUE && !rule.snoozing) { - proto.write(ZenModeProto.ENABLED_ACTIVE_CONDITIONS, rule.toString()); + rule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS); } } mConfig.toNotificationPolicy().writeToProto(proto, ZenModeProto.POLICY); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 776794593512..3049e98099ca 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -441,6 +441,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final int NFC_UID = Process.NFC_UID; private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID; private static final int SHELL_UID = Process.SHELL_UID; + private static final int SE_UID = Process.SE_UID; // Suffix used during package installation when copying/moving // package apks to install directory. @@ -2408,6 +2409,8 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); + mSettings.addSharedUserLPw("android.uid.se", SE_UID, + ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index cfdec4cc54bc..e3a6fa3bffc3 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -328,9 +328,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { * Skip immediately if intent is not relevant to device shutdown. */ if (!intent.getAction().equals(Intent.ACTION_REBOOT) - && !intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { - return; + && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN) + && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) { + return; } + Slog.i(TAG, "StatsCompanionService noticed a shutdown."); synchronized (sStatsdLock) { if (sStatsd == null) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 99712a5173db..8f6fac0566b9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -311,6 +311,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TAG_PRINTING_ENABLED = "printing-enabled"; + private static final String TAG_TRANSFER_OWNERSHIP_BUNDLE = "transfer-ownership-bundle"; + private static final int REQUEST_EXPIRE_PASSWORD = 5571; private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1); @@ -12624,6 +12626,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try (FileInputStream stream = new FileInputStream(bundleFile)) { XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, null); + parser.next(); return PersistableBundle.restoreFromXml(parser); } catch (IOException | XmlPullParserException | IllegalArgumentException e) { Slog.e(LOG_TAG, "Caught exception while trying to load the " @@ -12845,7 +12848,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(stream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); + serializer.startTag(null, TAG_TRANSFER_OWNERSHIP_BUNDLE); bundle.saveToXml(serializer); + serializer.endTag(null, TAG_TRANSFER_OWNERSHIP_BUNDLE); + serializer.endDocument(); atomicFile.finishWrite(stream); } catch (IOException | XmlPullParserException e) { Slog.e(LOG_TAG, "Caught exception while trying to save the " diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 6a3a260361c9..ce5ee138cc3d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -121,7 +121,7 @@ public class KeySyncTaskTest { TEST_CREDENTIAL_TYPE, TEST_CREDENTIAL, /*credentialUpdated=*/ false, - () -> mPlatformKeyManager); + mPlatformKeyManager); mWrappingKey = generateAndroidKeyStoreKey(); mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey); @@ -327,8 +327,7 @@ public class KeySyncTaskTest { mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true); - SecretKey applicationKey = - addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); mKeySyncTask.run(); @@ -343,6 +342,26 @@ public class KeySyncTaskTest { } @Test + public void run_recreatesMissingSnapshot() throws Exception { + mRecoverableKeyStoreDb.setRecoveryServicePublicKey( + TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); + when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true); + addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS); + + mKeySyncTask.run(); + + KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID); + assertThat(keyChainSnapshot.getSnapshotVersion()).isEqualTo(1); // default value; + + mRecoverySnapshotStorage.remove(TEST_RECOVERY_AGENT_UID); // corrupt snapshot. + + mKeySyncTask.run(); + + keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID); + assertThat(keyChainSnapshot.getSnapshotVersion()).isEqualTo(1); // Same version + } + + @Test public void run_setsCorrectTypeForPassword() throws Exception { mKeySyncTask = new KeySyncTask( mRecoverableKeyStoreDb, @@ -352,7 +371,7 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PASSWORD, "password", /*credentialUpdated=*/ false, - () -> mPlatformKeyManager); + mPlatformKeyManager); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); @@ -378,7 +397,7 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PASSWORD, /*credential=*/ "1234", /*credentialUpdated=*/ false, - () -> mPlatformKeyManager); + mPlatformKeyManager); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); @@ -405,7 +424,7 @@ public class KeySyncTaskTest { CREDENTIAL_TYPE_PATTERN, "12345", /*credentialUpdated=*/ false, - () -> mPlatformKeyManager); + mPlatformKeyManager); mRecoverableKeyStoreDb.setRecoveryServicePublicKey( TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic()); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index 6fc9e082bb7c..f9ffccdd5d38 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -252,6 +252,10 @@ public class PlatformKeyManagerTest { @Test public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/1/decrypt")).thenReturn(true); + mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( @@ -265,6 +269,13 @@ public class PlatformKeyManagerTest { eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), any()); + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/1/encrypt")).thenReturn(true); + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/2/encrypt")).thenReturn(true); + mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( @@ -282,19 +293,50 @@ public class PlatformKeyManagerTest { eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), any()); + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/1/decrypt")).thenReturn(false); // was removed. + + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/2/decrypt")).thenReturn(true); // new version is available + mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); + verify(mKeyStoreProxy).containsAlias( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt")); + // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( - eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), any()); + } + + @Test + public void getEncryptKey_generatesNewKeyIfOldWasRemoved() throws Exception { + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/1/encrypt")).thenReturn(false); // was removed. + + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/2/encrypt")).thenReturn(true); // new version is available + + mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); + + verify(mKeyStoreProxy).containsAlias( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); // Attempt to get regenerated key. verify(mKeyStoreProxy).getKey( - eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), any()); } @Test - public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { + public void getEncryptKey_getsEndryptKeyWithCorrectAlias() throws Exception { + when(mKeyStoreProxy + .containsAlias("com.android.server.locksettings.recoverablekeystore/" + + "platform/42/1/encrypt")).thenReturn(true); + mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( @@ -312,6 +354,26 @@ public class PlatformKeyManagerTest { } @Test + public void regenerate_deletesOldKeysFromKeystore() throws Exception { + mPlatformKeyManager.init(USER_ID_FIXTURE); + + mPlatformKeyManager.regenerate(USER_ID_FIXTURE); + + verify(mKeyStoreProxy).deleteEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt")); + verify(mKeyStoreProxy).deleteEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt")); + + mPlatformKeyManager.regenerate(USER_ID_FIXTURE); + + // Removes second generation keys. + verify(mKeyStoreProxy).deleteEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt")); + verify(mKeyStoreProxy).deleteEntry( + eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt")); + } + + @Test public void regenerate_generatesANewEncryptKeyWithTheCorrectAlias() throws Exception { mPlatformKeyManager.init(USER_ID_FIXTURE); diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java index c7fa62e56380..376db5bbad67 100644 --- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java +++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java @@ -388,7 +388,8 @@ public class ConnOnActivityStartTest { latch.countDown(); } }); - launchIntent.putExtras(extras); + launchIntent.putExtras(extras) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(launchIntent); if (latch.await(NETWORK_CHECK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { if (errors[0] != null) { diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java index 0cbda2845e53..2becdf230dbc 100644 --- a/services/usage/java/com/android/server/usage/AppIdleHistory.java +++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java @@ -36,6 +36,8 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.LocalServices; +import com.android.server.job.JobSchedulerInternal; import libcore.io.IoUtils; @@ -202,27 +204,23 @@ public class AppIdleHistory { * that's in the future, then the usage event is temporary and keeps the app in the specified * bucket at least until the timeout is reached. This can be used to keep the app in an * elevated bucket for a while until some important task gets to run. - * @param packageName - * @param userId - * @param bucket the bucket to set the app to + * @param appUsageHistory the usage record for the app being updated + * @param packageName name of the app being updated, for logging purposes + * @param newBucket the bucket to set the app to * @param elapsedRealtime mark as used time if non-zero * @param timeout set the timeout of the specified bucket, if non-zero * @return */ - public int reportUsage(String packageName, int userId, int bucket, long elapsedRealtime, - long timeout) { - ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); - AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, - elapsedRealtime, true); - + public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName, + int newBucket, long elapsedRealtime, long timeout) { if (elapsedRealtime != 0) { appUsageHistory.lastUsedElapsedTime = mElapsedDuration + (elapsedRealtime - mElapsedSnapshot); appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime); } - if (appUsageHistory.currentBucket > bucket) { - appUsageHistory.currentBucket = bucket; + if (appUsageHistory.currentBucket > newBucket) { + appUsageHistory.currentBucket = newBucket; if (DEBUG) { Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory .currentBucket @@ -235,7 +233,26 @@ public class AppIdleHistory { } appUsageHistory.bucketingReason = REASON_USAGE; - return appUsageHistory.currentBucket; + return appUsageHistory; + } + + /** + * Mark the app as used and update the bucket if necessary. If there is a timeout specified + * that's in the future, then the usage event is temporary and keeps the app in the specified + * bucket at least until the timeout is reached. This can be used to keep the app in an + * elevated bucket for a while until some important task gets to run. + * @param packageName + * @param userId + * @param newBucket the bucket to set the app to + * @param elapsedRealtime mark as used time if non-zero + * @param timeout set the timeout of the specified bucket, if non-zero + * @return + */ + public AppUsageHistory reportUsage(String packageName, int userId, int newBucket, + long nowElapsed, long timeout) { + ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); + AppUsageHistory history = getPackageHistory(userHistory, packageName, nowElapsed, true); + return reportUsage(history, packageName, newBucket, nowElapsed, timeout); } private ArrayMap<String, AppUsageHistory> getUserHistory(int userId) { diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 6782188c0f34..8cb2eecc654a 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -27,7 +27,6 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; - import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; @@ -81,6 +80,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; +import com.android.server.usage.AppIdleHistory.AppUsageHistory; import java.io.File; import java.io.PrintWriter; @@ -198,6 +198,48 @@ public class AppStandbyController { private PackageManager mPackageManager; Injector mInjector; + static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4); + + public static class StandbyUpdateRecord { + // Identity of the app whose standby state has changed + String packageName; + int userId; + + // What the standby bucket the app is now in + int bucket; + + // Whether the bucket change is because the user has started interacting with the app + boolean isUserInteraction; + + StandbyUpdateRecord(String pkgName, int userId, int bucket, boolean isInteraction) { + this.packageName = pkgName; + this.userId = userId; + this.bucket = bucket; + this.isUserInteraction = isInteraction; + } + + public static StandbyUpdateRecord obtain(String pkgName, int userId, + int bucket, boolean isInteraction) { + synchronized (sStandbyUpdatePool) { + final int size = sStandbyUpdatePool.size(); + if (size < 1) { + return new StandbyUpdateRecord(pkgName, userId, bucket, isInteraction); + } + StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1); + r.packageName = pkgName; + r.userId = userId; + r.bucket = bucket; + r.isUserInteraction = isInteraction; + return r; + } + } + + public void recycle() { + synchronized (sStandbyUpdatePool) { + sStandbyUpdatePool.add(this); + } + } + } AppStandbyController(Context context, Looper looper) { this(new Injector(context, looper)); @@ -279,11 +321,11 @@ public class AppStandbyController { } if (!packageName.equals(providerPkgName)) { synchronized (mAppIdleLock) { - int newBucket = mAppIdleHistory.reportUsage(packageName, userId, + AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR); maybeInformListeners(packageName, userId, elapsedRealtime, - newBucket); + appUsage.currentBucket, false); } } } catch (PackageManager.NameNotFoundException e) { @@ -417,7 +459,7 @@ public class AppStandbyController { STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT); } maybeInformListeners(packageName, userId, elapsedRealtime, - STANDBY_BUCKET_EXEMPTED); + STANDBY_BUCKET_EXEMPTED, false); } else { synchronized (mAppIdleLock) { AppIdleHistory.AppUsageHistory app = @@ -446,7 +488,7 @@ public class AppStandbyController { mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, REASON_TIMEOUT); maybeInformListeners(packageName, userId, elapsedRealtime, - newBucket); + newBucket, false); } } } @@ -474,13 +516,16 @@ public class AppStandbyController { } private void maybeInformListeners(String packageName, int userId, - long elapsedRealtime, int bucket) { + long elapsedRealtime, int bucket, boolean userStartedInteracting) { synchronized (mAppIdleLock) { // TODO: fold these into one call + lookup for efficiency if needed if (mAppIdleHistory.shouldInformListeners(packageName, userId, elapsedRealtime, bucket)) { + StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId, + bucket, userStartedInteracting); mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, - userId, bucket, packageName)); + StandbyUpdateRecord.obtain(packageName, userId, + bucket, userStartedInteracting))); } } } @@ -566,19 +611,27 @@ public class AppStandbyController { || event.mEventType == UsageEvents.Event.USER_INTERACTION || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN)) { - final int newBucket; + final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( + event.mPackage, userId, elapsedRealtime); + final int prevBucket = appHistory.currentBucket; + final String prevBucketReason = appHistory.bucketingReason; if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) { - newBucket = mAppIdleHistory.reportUsage(event.mPackage, userId, + mAppIdleHistory.reportUsage(appHistory, event.mPackage, STANDBY_BUCKET_WORKING_SET, elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR); } else { - newBucket = mAppIdleHistory.reportUsage(event.mPackage, userId, + mAppIdleHistory.reportUsage(event.mPackage, userId, STANDBY_BUCKET_ACTIVE, elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR); } + final boolean userStartedInteracting = + appHistory.currentBucket == STANDBY_BUCKET_ACTIVE && + prevBucket != appHistory.currentBucket && + prevBucketReason != REASON_USAGE; maybeInformListeners(event.mPackage, userId, elapsedRealtime, - newBucket); + appHistory.currentBucket, userStartedInteracting); + if (previouslyIdle) { notifyBatteryStats(event.mPackage, userId, false); } @@ -611,7 +664,7 @@ public class AppStandbyController { userId, elapsedRealtime); // Inform listeners if necessary if (previouslyIdle != stillIdle) { - maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket); + maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, false); if (!stillIdle) { notifyBatteryStats(packageName, userId, idle); } @@ -871,8 +924,7 @@ public class AppStandbyController { mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason); } - maybeInformListeners(packageName, userId, elapsedRealtime, - newBucket); + maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, false); } @VisibleForTesting @@ -972,11 +1024,14 @@ public class AppStandbyController { return packageName != null && packageName.equals(activeScorer); } - void informListeners(String packageName, int userId, int bucket) { + void informListeners(String packageName, int userId, int bucket, boolean userInteraction) { final boolean idle = bucket >= STANDBY_BUCKET_RARE; synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onAppIdleStateChanged(packageName, userId, idle, bucket); + if (userInteraction) { + listener.onUserInteractionStarted(packageName, userId); + } } } } @@ -1230,7 +1285,9 @@ public class AppStandbyController { public void handleMessage(Message msg) { switch (msg.what) { case MSG_INFORM_LISTENERS: - informListeners((String) msg.obj, msg.arg1, msg.arg2); + StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj; + informListeners(r.packageName, r.userId, r.bucket, r.isUserInteraction); + r.recycle(); break; case MSG_FORCE_IDLE_STATE: diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 096fdcc24030..36a2a95dd1e1 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1043,6 +1043,12 @@ public class UsageStatsService extends SystemService implements return mAppStandby.getTimeSinceLastJobRun(packageName, userId); } + @Override + public void reportAppJobState(String packageName, int userId, + int numDeferredJobs, long timeSinceLastJobRun) { + } + + @Override public void onActiveAdminAdded(String packageName, int userId) { mAppStandby.addActiveDeviceAdmin(packageName, userId); } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index fa19ea069044..c4f9022c31ce 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -86,15 +86,17 @@ public abstract class DataService extends Service { /** The reason of the data request is IWLAN handover */ public static final int REQUEST_REASON_HANDOVER = 3; - private static final int DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE = 1; - private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL = 2; - private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL = 3; - private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN = 4; - private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE = 5; - private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST = 6; - private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED = 7; - private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED = 8; - private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED = 9; + private static final int DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER = 1; + private static final int DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER = 2; + private static final int DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS = 3; + private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL = 4; + private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL = 5; + private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN = 6; + private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE = 7; + private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST = 8; + private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED = 9; + private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED = 10; + private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED = 11; private final HandlerThread mHandlerThread; @@ -102,7 +104,7 @@ public abstract class DataService extends Service { private final SparseArray<DataServiceProvider> mServiceMap = new SparseArray<>(); - private final SparseArray<IDataServiceWrapper> mBinderMap = new SparseArray<>(); + private final IBinder mBinder = new IDataServiceWrapper(); /** * The abstract class of the actual data service implementation. The data service provider @@ -321,23 +323,34 @@ public abstract class DataService extends Service { public void handleMessage(Message message) { IDataServiceCallback callback; final int slotId = message.arg1; - DataServiceProvider service; - - synchronized (mServiceMap) { - service = mServiceMap.get(slotId); - } + DataServiceProvider serviceProvider = mServiceMap.get(slotId); switch (message.what) { - case DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE: - service = createDataServiceProvider(message.arg1); - if (service != null) { - mServiceMap.put(slotId, service); + case DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER: + serviceProvider = createDataServiceProvider(message.arg1); + if (serviceProvider != null) { + mServiceMap.put(slotId, serviceProvider); } break; + case DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER: + if (serviceProvider != null) { + serviceProvider.onDestroy(); + mServiceMap.remove(slotId); + } + break; + case DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS: + for (int i = 0; i < mServiceMap.size(); i++) { + serviceProvider = mServiceMap.get(i); + if (serviceProvider != null) { + serviceProvider.onDestroy(); + } + } + mServiceMap.clear(); + break; case DATA_SERVICE_REQUEST_SETUP_DATA_CALL: - if (service == null) break; + if (serviceProvider == null) break; SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj; - service.setupDataCall(setupDataCallRequest.accessNetworkType, + serviceProvider.setupDataCall(setupDataCallRequest.accessNetworkType, setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming, setupDataCallRequest.allowRoaming, setupDataCallRequest.reason, setupDataCallRequest.linkProperties, @@ -345,46 +358,46 @@ public abstract class DataService extends Service { break; case DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL: - if (service == null) break; + if (serviceProvider == null) break; DeactivateDataCallRequest deactivateDataCallRequest = (DeactivateDataCallRequest) message.obj; - service.deactivateDataCall(deactivateDataCallRequest.cid, + serviceProvider.deactivateDataCall(deactivateDataCallRequest.cid, deactivateDataCallRequest.reason, new DataServiceCallback(deactivateDataCallRequest.callback)); break; case DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN: - if (service == null) break; + if (serviceProvider == null) break; SetInitialAttachApnRequest setInitialAttachApnRequest = (SetInitialAttachApnRequest) message.obj; - service.setInitialAttachApn(setInitialAttachApnRequest.dataProfile, + serviceProvider.setInitialAttachApn(setInitialAttachApnRequest.dataProfile, setInitialAttachApnRequest.isRoaming, new DataServiceCallback(setInitialAttachApnRequest.callback)); break; case DATA_SERVICE_REQUEST_SET_DATA_PROFILE: - if (service == null) break; + if (serviceProvider == null) break; SetDataProfileRequest setDataProfileRequest = (SetDataProfileRequest) message.obj; - service.setDataProfile(setDataProfileRequest.dps, + serviceProvider.setDataProfile(setDataProfileRequest.dps, setDataProfileRequest.isRoaming, new DataServiceCallback(setDataProfileRequest.callback)); break; case DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST: - if (service == null) break; + if (serviceProvider == null) break; - service.getDataCallList(new DataServiceCallback( + serviceProvider.getDataCallList(new DataServiceCallback( (IDataServiceCallback) message.obj)); break; case DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED: - if (service == null) break; - service.registerForDataCallListChanged((IDataServiceCallback) message.obj); + if (serviceProvider == null) break; + serviceProvider.registerForDataCallListChanged((IDataServiceCallback) message.obj); break; case DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED: - if (service == null) break; + if (serviceProvider == null) break; callback = (IDataServiceCallback) message.obj; - service.unregisterForDataCallListChanged(callback); + serviceProvider.unregisterForDataCallListChanged(callback); break; case DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED: - if (service == null) break; + if (serviceProvider == null) break; DataCallListChangedIndication indication = (DataCallListChangedIndication) message.obj; try { @@ -423,67 +436,19 @@ public abstract class DataService extends Service { loge("Unexpected intent " + intent); return null; } - - int slotId = intent.getIntExtra( - DATA_SERVICE_EXTRA_SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX); - - if (!SubscriptionManager.isValidSlotIndex(slotId)) { - loge("Invalid slot id " + slotId); - return null; - } - - log("onBind: slot id=" + slotId); - - IDataServiceWrapper binder = mBinderMap.get(slotId); - if (binder == null) { - Message msg = mHandler.obtainMessage(DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE); - msg.arg1 = slotId; - msg.sendToTarget(); - - binder = new IDataServiceWrapper(slotId); - mBinderMap.put(slotId, binder); - } - - return binder; + return mBinder; } /** @hide */ @Override public boolean onUnbind(Intent intent) { - int slotId = intent.getIntExtra(DATA_SERVICE_EXTRA_SLOT_ID, - SubscriptionManager.INVALID_SIM_SLOT_INDEX); - if (mBinderMap.get(slotId) != null) { - DataServiceProvider serviceImpl; - synchronized (mServiceMap) { - serviceImpl = mServiceMap.get(slotId); - } - if (serviceImpl != null) { - serviceImpl.onDestroy(); - } - mBinderMap.remove(slotId); - } - - // If all clients unbinds, quit the handler thread - if (mBinderMap.size() == 0) { - mHandlerThread.quit(); - } - + mHandler.obtainMessage(DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS).sendToTarget(); return false; } /** @hide */ @Override public void onDestroy() { - synchronized (mServiceMap) { - for (int i = 0; i < mServiceMap.size(); i++) { - DataServiceProvider serviceImpl = mServiceMap.get(i); - if (serviceImpl != null) { - serviceImpl.onDestroy(); - } - } - mServiceMap.clear(); - } - mHandlerThread.quit(); } @@ -491,68 +456,74 @@ public abstract class DataService extends Service { * A wrapper around IDataService that forwards calls to implementations of {@link DataService}. */ private class IDataServiceWrapper extends IDataService.Stub { + @Override + public void createDataServiceProvider(int slotId) { + mHandler.obtainMessage(DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER, slotId, 0) + .sendToTarget(); + } - private final int mSlotId; - - IDataServiceWrapper(int slotId) { - mSlotId = slotId; + @Override + public void removeDataServiceProvider(int slotId) { + mHandler.obtainMessage(DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER, slotId, 0) + .sendToTarget(); } @Override - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, + public void setupDataCall(int slotId, int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, IDataServiceCallback callback) { - mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, mSlotId, 0, + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotId, 0, new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, linkProperties, callback)) .sendToTarget(); } @Override - public void deactivateDataCall(int cid, int reason, IDataServiceCallback callback) { - mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, mSlotId, 0, + public void deactivateDataCall(int slotId, int cid, int reason, + IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, slotId, 0, new DeactivateDataCallRequest(cid, reason, callback)) .sendToTarget(); } @Override - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, + public void setInitialAttachApn(int slotId, DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback) { - mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN, mSlotId, 0, + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN, slotId, 0, new SetInitialAttachApnRequest(dataProfile, isRoaming, callback)) .sendToTarget(); } @Override - public void setDataProfile(List<DataProfile> dps, boolean isRoaming, + public void setDataProfile(int slotId, List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback) { - mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_DATA_PROFILE, mSlotId, 0, + mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_DATA_PROFILE, slotId, 0, new SetDataProfileRequest(dps, isRoaming, callback)).sendToTarget(); } @Override - public void getDataCallList(IDataServiceCallback callback) { - mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, mSlotId, 0, + public void getDataCallList(int slotId, IDataServiceCallback callback) { + mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, slotId, 0, callback).sendToTarget(); } @Override - public void registerForDataCallListChanged(IDataServiceCallback callback) { + public void registerForDataCallListChanged(int slotId, IDataServiceCallback callback) { if (callback == null) { loge("Callback is null"); return; } - mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED, mSlotId, + mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED, slotId, 0, callback).sendToTarget(); } @Override - public void unregisterForDataCallListChanged(IDataServiceCallback callback) { + public void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback) { if (callback == null) { loge("Callback is null"); return; } - mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED, mSlotId, + mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED, slotId, 0, callback).sendToTarget(); } } diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index b6a81f94028b..08f33d948061 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -18,6 +18,7 @@ package android.telephony.data; import android.annotation.IntDef; import android.annotation.SystemApi; +import android.net.LinkProperties; import android.os.RemoteException; import android.telephony.Rlog; import android.telephony.data.DataService.DataServiceProvider; @@ -46,7 +47,7 @@ public class DataServiceCallback { @Retention(RetentionPolicy.SOURCE) @IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY, RESULT_ERROR_ILLEGAL_STATE}) - public @interface Result {} + public @interface ResultCode {} /** Request is completed successfully */ public static final int RESULT_SUCCESS = 0; @@ -68,12 +69,12 @@ public class DataServiceCallback { /** * Called to indicate result for the request {@link DataServiceProvider#setupDataCall(int, - * DataProfile, boolean, boolean, boolean, DataServiceCallback)}. + * DataProfile, boolean, boolean, int, LinkProperties, DataServiceCallback)} . * - * @param result The result code. Must be one of the {@link Result}. + * @param result The result code. Must be one of the {@link ResultCode}. * @param response Setup data call response. */ - public void onSetupDataCallComplete(@Result int result, DataCallResponse response) { + public void onSetupDataCallComplete(@ResultCode int result, DataCallResponse response) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { @@ -86,11 +87,11 @@ public class DataServiceCallback { /** * Called to indicate result for the request {@link DataServiceProvider#deactivateDataCall(int, - * boolean, boolean, DataServiceCallback)}. + * int, DataServiceCallback)} * - * @param result The result code. Must be one of the {@link Result}. + * @param result The result code. Must be one of the {@link ResultCode}. */ - public void onDeactivateDataCallComplete(@Result int result) { + public void onDeactivateDataCallComplete(@ResultCode int result) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { @@ -105,9 +106,9 @@ public class DataServiceCallback { * Called to indicate result for the request {@link DataServiceProvider#setInitialAttachApn( * DataProfile, boolean, DataServiceCallback)}. * - * @param result The result code. Must be one of the {@link Result}. + * @param result The result code. Must be one of the {@link ResultCode}. */ - public void onSetInitialAttachApnComplete(@Result int result) { + public void onSetInitialAttachApnComplete(@ResultCode int result) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { @@ -122,10 +123,10 @@ public class DataServiceCallback { * Called to indicate result for the request {@link DataServiceProvider#setDataProfile(List, * boolean, DataServiceCallback)}. * - * @param result The result code. Must be one of the {@link Result}. + * @param result The result code. Must be one of the {@link ResultCode}. */ @SystemApi - public void onSetDataProfileComplete(@Result int result) { + public void onSetDataProfileComplete(@ResultCode int result) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { @@ -140,10 +141,11 @@ public class DataServiceCallback { * Called to indicate result for the request {@link DataServiceProvider#getDataCallList( * DataServiceCallback)}. * - * @param result The result code. Must be one of the {@link Result}. + * @param result The result code. Must be one of the {@link ResultCode}. * @param dataCallList List of the current active data connection. */ - public void onGetDataCallListComplete(@Result int result, List<DataCallResponse> dataCallList) { + public void onGetDataCallListComplete(@ResultCode int result, + List<DataCallResponse> dataCallList) { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index 07720b69e45f..d4d9be85ffa8 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -25,14 +25,17 @@ import android.telephony.data.IDataServiceCallback; */ oneway interface IDataService { - void setupDataCall(int accessNetwork, in DataProfile dataProfile, boolean isRoaming, + void createDataServiceProvider(int slotId); + void removeDataServiceProvider(int slotId); + void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, in LinkProperties linkProperties, IDataServiceCallback callback); - void deactivateDataCall(int cid, int reason, IDataServiceCallback callback); - void setInitialAttachApn(in DataProfile dataProfile, boolean isRoaming, + void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback); + void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback); - void setDataProfile(in List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback); - void getDataCallList(IDataServiceCallback callback); - void registerForDataCallListChanged(IDataServiceCallback callback); - void unregisterForDataCallListChanged(IDataServiceCallback callback); + void setDataProfile(int slotId, in List<DataProfile> dps, boolean isRoaming, + IDataServiceCallback callback); + void getDataCallList(int slotId, IDataServiceCallback callback); + void registerForDataCallListChanged(int slotId, IDataServiceCallback callback); + void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback); } diff --git a/test-mock/Android.mk b/test-mock/Android.mk index 7926a77ccb01..5c586c7101a1 100644 --- a/test-mock/Android.mk +++ b/test-mock/Android.mk @@ -31,7 +31,7 @@ ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK))) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(android_test_mock_source_files) -LOCAL_JAVA_LIBRARIES := core-oj core-libart framework +LOCAL_JAVA_LIBRARIES := core-oj core-libart framework conscrypt okhttp bouncycastle LOCAL_MODULE_CLASS := JAVA_LIBRARIES LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock @@ -116,7 +116,7 @@ update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(android_test_mock_source_files) -LOCAL_JAVA_LIBRARIES := core-oj core-libart framework +LOCAL_JAVA_LIBRARIES := core-oj core-libart framework conscrypt okhttp bouncycastle LOCAL_MODULE_CLASS := JAVA_LIBRARIES LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock diff --git a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java index 6787594b829c..0c3bf3b9ef2e 100644 --- a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java +++ b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java index 689ebbafe527..458c43dcd692 100644 --- a/wifi/tests/src/android/net/wifi/ScanResultTest.java +++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertNull; import static org.mockito.Mockito.validateMockitoUsage; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.net.wifi.WifiScanner.ScanSettings; import org.junit.After; diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java index 1a7dd132389e..e569efef5d91 100644 --- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java +++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java @@ -28,7 +28,7 @@ import android.net.wifi.WifiEnterpriseConfig.Eap; import android.net.wifi.WifiEnterpriseConfig.Phase2; import android.os.Parcel; import android.security.Credentials; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 4b5f6452d392..7259695446a1 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -51,7 +51,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java index a4366d454a67..96d5a5167480 100644 --- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java @@ -25,7 +25,7 @@ import android.content.Context; import android.os.Handler; import android.os.Parcel; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.net.wifi.WifiScanner.ScanSettings; import com.android.internal.util.test.BidirectionalAsyncChannelServer; diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java index 15641abd11f9..6ecd93114dc2 100644 --- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java +++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java @@ -18,7 +18,7 @@ package android.net.wifi.aware; import static org.hamcrest.core.IsEqual.equalTo; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Rule; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java index 2dd0537a7aff..0515e0637e03 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java @@ -20,7 +20,7 @@ import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Rule; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 9cab66a240a7..b0a048d77730 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -31,7 +31,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.test.TestLooper; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import libcore.util.HexEncoding; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java index 56bb4375acdd..f32fe599cd95 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; import android.net.wifi.FakeKeys; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import java.io.BufferedReader; import java.io.IOException; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java index 9670bfab89f8..d3f91f06da61 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java @@ -23,7 +23,7 @@ import android.graphics.drawable.Icon; import android.net.Uri; import android.net.wifi.WifiSsid; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index afcf3e344c27..940adc809535 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -25,7 +25,7 @@ import android.net.wifi.hotspot2.pps.HomeSp; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.util.Base64; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java index afa9fd6a9e8b..707b64f780c5 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java @@ -25,7 +25,7 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.text.TextUtils; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java index c2dcec693b83..ef478c7a105c 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertTrue; import android.net.wifi.hotspot2.omadm.XMLNode; import android.net.wifi.hotspot2.omadm.XMLParser; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index 9bfc0105fcc9..b573adf60863 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; import android.net.wifi.EAPConstants; import android.net.wifi.FakeKeys; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java index c41c11f16acf..5c9df6a0186c 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java index 2a3676463936..171d6ff0781f 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.util.Base64; import org.junit.Test; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java index 551ed43c5efa..2a7526bc3de6 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; import android.util.Base64; import org.junit.Test; |