Merge "Add support for render-ahead"
diff --git a/api/current.txt b/api/current.txt
index 712475e..5b5bd24 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27276,7 +27276,6 @@
method public int describeContents();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
- method public boolean hasUnwantedCapability(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
}
@@ -27285,7 +27284,6 @@
ctor public NetworkRequest.Builder();
method public android.net.NetworkRequest.Builder addCapability(int);
method public android.net.NetworkRequest.Builder addTransportType(int);
- method public android.net.NetworkRequest.Builder addUnwantedCapability(int);
method public android.net.NetworkRequest build();
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
diff --git a/api/removed.txt b/api/removed.txt
index fd48f24..4e730c2 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -296,6 +296,14 @@
public static abstract class NetworkBadging.Badging implements java.lang.annotation.Annotation {
}
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean hasUnwantedCapability(int);
+ }
+
+ public static class NetworkRequest.Builder {
+ method public android.net.NetworkRequest.Builder addUnwantedCapability(int);
+ }
+
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 15f3400..d5b1399 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -245,6 +245,8 @@
method public abstract int getInstallReason(java.lang.String, android.os.UserHandle);
method public abstract java.lang.String[] getNamesForUids(int[]);
method public abstract java.lang.String getPermissionControllerPackageName();
+ method public abstract java.lang.String getServicesSystemSharedLibraryPackageName();
+ method public abstract java.lang.String getSharedSystemSharedLibraryPackageName();
method public abstract boolean isPermissionReviewModeEnabled();
field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final java.lang.String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
@@ -465,10 +467,18 @@
method public void setType(int);
}
+ public class LocationManager {
+ method public java.lang.String[] getBackgroundThrottlingWhitelist();
+ }
+
}
package android.media {
+ public final class AudioFocusRequest {
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ }
+
public final class AudioFormat implements android.os.Parcelable {
method public static int channelCountFromInChannelMask(int);
method public static int channelCountFromOutChannelMask(int);
@@ -476,6 +486,17 @@
method public static boolean isEncodingLinearPcm(int);
}
+ public final class AudioPresentation {
+ ctor public AudioPresentation(int, int, java.util.Map<java.lang.String, java.lang.String>, java.lang.String, int, boolean, boolean, boolean);
+ method public int getPresentationId();
+ method public int getProgramId();
+ }
+
+ public final class PlaybackParams implements android.os.Parcelable {
+ method public int getAudioStretchMode();
+ method public android.media.PlaybackParams setAudioStretchMode(int);
+ }
+
public static final class VolumeShaper.Configuration.Builder {
method public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
}
@@ -534,6 +555,15 @@
field public static final int RESOURCES_SDK_INT;
}
+ public class DeviceIdleManager {
+ method public java.lang.String[] getSystemPowerWhitelist();
+ method public java.lang.String[] getSystemPowerWhitelistExceptIdle();
+ }
+
+ public class Environment {
+ method public static java.io.File buildPath(java.io.File, java.lang.String...);
+ }
+
public class IncidentManager {
method public void reportIncident(android.os.IncidentReportArgs);
}
@@ -601,12 +631,18 @@
method public abstract void log(android.os.StrictMode.ViolationInfo);
}
+ public class SystemProperties {
+ method public static java.lang.String get(java.lang.String, java.lang.String);
+ }
+
public final class UserHandle implements android.os.Parcelable {
method public static int getAppId(int);
method public int getIdentifier();
+ field public static final android.os.UserHandle SYSTEM;
}
public class UserManager {
+ method public static boolean isSplitSystemUser();
field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f16109c..d3cda63 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -178,23 +178,34 @@
}
bool verbose = false;
+ bool proto = false;
if (args.size() > 0 && !args[0].compare(String16("-v"))) {
verbose = true;
}
+ if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) {
+ proto = true;
+ }
- // TODO: Proto format for incident reports
- dump_impl(out, verbose);
+ dump_impl(out, verbose, proto);
fclose(out);
return NO_ERROR;
}
/**
- * Write debugging data about statsd in text format.
+ * Write debugging data about statsd in text or proto format.
*/
-void StatsService::dump_impl(FILE* out, bool verbose) {
- StatsdStats::getInstance().dumpStats(out);
- mProcessor->dumpStates(out, verbose);
+void StatsService::dump_impl(FILE* out, bool verbose, bool proto) {
+ if (proto) {
+ vector<uint8_t> data;
+ StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
+ for (size_t i = 0; i < data.size(); i ++) {
+ fprintf(out, "%c", data[i]);
+ }
+ } else {
+ StatsdStats::getInstance().dumpStats(out);
+ mProcessor->dumpStates(out, verbose);
+ }
}
/**
@@ -325,6 +336,7 @@
fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats print-stats\n");
fprintf(out, " Prints some basic stats.\n");
+ fprintf(out, " --proto Print proto binary instead of string format.\n");
fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
@@ -524,13 +536,28 @@
}
status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) {
- vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
- for (const ConfigKey& key : configs) {
- fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
- mProcessor->GetMetricsSize(key));
+ int argCount = args.size();
+ bool proto = false;
+ if (!std::strcmp("--proto", args[argCount-1].c_str())) {
+ proto = true;
+ argCount -= 1;
}
StatsdStats& statsdStats = StatsdStats::getInstance();
- statsdStats.dumpStats(out);
+ if (proto) {
+ vector<uint8_t> data;
+ statsdStats.dumpStats(&data, false); // does not reset statsdStats.
+ for (size_t i = 0; i < data.size(); i ++) {
+ fprintf(out, "%c", data[i]);
+ }
+
+ } else {
+ vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
+ for (const ConfigKey& key : configs) {
+ fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
+ mProcessor->GetMetricsSize(key));
+ }
+ statsdStats.dumpStats(out);
+ }
return NO_ERROR;
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index a4552e1..648e9c5 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -149,9 +149,9 @@
uint32_t serial);
/**
- * Text output of dumpsys.
+ * Text or proto output of dumpsys.
*/
- void dump_impl(FILE* out, bool verbose);
+ void dump_impl(FILE* out, bool verbose, bool proto);
/**
* Print usage information for the commands
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 290f8ac..44543a7 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1512,7 +1512,6 @@
Landroid/os/UserHandle;->MU_ENABLED:Z
Landroid/os/UserHandle;->OWNER:Landroid/os/UserHandle;
Landroid/os/UserHandle;->PER_USER_RANGE:I
-Landroid/os/UserHandle;->SYSTEM:Landroid/os/UserHandle;
Landroid/os/UserHandle;->USER_ALL:I
Landroid/os/UserHandle;->USER_CURRENT:I
Landroid/os/UserHandle;->USER_CURRENT_OR_SELF:I
@@ -2245,7 +2244,6 @@
Landroid/view/SurfaceView;->mSurfaceHolder:Landroid/view/SurfaceHolder;
Landroid/view/SurfaceView;->surfacePositionLost_uiRtSync(J)V
Landroid/view/SurfaceView;->updateSurfacePosition_renderWorker(JIIII)V
-Landroid/view/textclassifier/Logger;->DISABLED:Landroid/view/textclassifier/Logger;
Landroid/view/textclassifier/logging/SmartSelectionEventTracker;-><init>(Landroid/content/Context;I)V
Landroid/view/textclassifier/logging/SmartSelectionEventTracker;->logEvent(Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;)V
Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(III)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 09dcbf2..ecd99a7 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1139,7 +1139,8 @@
* {@link android.app.admin.DevicePolicyManager} can run in LockTask mode. Therefore, if
* {@link android.app.admin.DevicePolicyManager#isLockTaskPermitted(String)} returns
* {@code false} for the package of the target activity, a {@link SecurityException} will be
- * thrown during {@link Context#startActivity(Intent, Bundle)}.
+ * thrown during {@link Context#startActivity(Intent, Bundle)}. This method doesn't affect
+ * activities that are already running — relaunch the activity to run in lock task mode.
*
* Defaults to {@code false} if not set.
*
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8719875..4ab6724 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6431,6 +6431,7 @@
/**
* @return the user to be displayed for any replies sent by the user
*/
+ @NonNull
public Person getUser() {
return mUser;
}
@@ -6505,7 +6506,8 @@
*
* @return this object for method chaining
*/
- public MessagingStyle addMessage(CharSequence text, long timestamp, Person sender) {
+ public MessagingStyle addMessage(@NonNull CharSequence text, long timestamp,
+ @Nullable Person sender) {
return addMessage(new Message(text, timestamp, sender));
}
@@ -6935,7 +6937,7 @@
* to differentiate between the different users.
* </p>
*/
- public Message(CharSequence text, long timestamp, @Nullable Person sender){
+ public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender) {
mText = text;
mTimestamp = timestamp;
mSender = sender;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 46d1264..5113fd0 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1145,6 +1145,21 @@
SUPPRESSED_EFFECT_NOTIFICATION_LIST
};
+ private static final int[] SCREEN_OFF_SUPPRESSED_EFFECTS = {
+ SUPPRESSED_EFFECT_SCREEN_OFF,
+ SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ SUPPRESSED_EFFECT_LIGHTS,
+ SUPPRESSED_EFFECT_AMBIENT,
+ };
+
+ private static final int[] SCREEN_ON_SUPPRESSED_EFFECTS = {
+ SUPPRESSED_EFFECT_SCREEN_ON,
+ SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_STATUS_BAR,
+ SUPPRESSED_EFFECT_BADGE,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST
+ };
+
/**
* Visual effects to suppress for a notification that is filtered by Do Not Disturb mode.
* Bitmask of SUPPRESSED_EFFECT_* constants.
@@ -1297,6 +1312,32 @@
return true;
}
+ /**
+ * @hide
+ */
+ public static boolean areAnyScreenOffEffectsSuppressed(int effects) {
+ for (int i = 0; i < SCREEN_OFF_SUPPRESSED_EFFECTS.length; i++) {
+ final int effect = SCREEN_OFF_SUPPRESSED_EFFECTS[i];
+ if ((effects & effect) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean areAnyScreenOnEffectsSuppressed(int effects) {
+ for (int i = 0; i < SCREEN_ON_SUPPRESSED_EFFECTS.length; i++) {
+ final int effect = SCREEN_ON_SUPPRESSED_EFFECTS[i];
+ if ((effects & effect) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static String suppressedEffectsToString(int effects) {
if (effects <= 0) return "";
final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index 47741c0..c174665 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -122,6 +122,7 @@
public RemoteAction clone() {
RemoteAction action = new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent);
action.setEnabled(mEnabled);
+ action.setShouldShowIcon(mShouldShowIcon);
return action;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3ee1ed5..246d4a3 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -105,10 +105,12 @@
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
+import android.os.DeviceIdleManager;
import android.os.DropBoxManager;
import android.os.HardwarePropertiesManager;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
+import android.os.IDeviceIdleController;
import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
@@ -984,6 +986,17 @@
ctx.mMainThread.getHandler());
}
});
+
+ registerService(Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class,
+ new CachedServiceFetcher<DeviceIdleManager>() {
+ @Override
+ public DeviceIdleManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IDeviceIdleController service = IDeviceIdleController.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(
+ Context.DEVICE_IDLE_CONTROLLER));
+ return new DeviceIdleManager(ctx.getOuterContext(), service);
+ }});
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 465340f..17bc6ea 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -401,7 +401,8 @@
}
}
synchronized (this) {
- if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) {
+ if (mCachedWallpaper != null && mCachedWallpaperUserId == userId
+ && !mCachedWallpaper.isRecycled()) {
return mCachedWallpaper;
}
mCachedWallpaper = null;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8f1b328..990147b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6198,6 +6198,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public @Nullable List<String> getPermittedAccessibilityServices(int userId) {
throwIfParentInstance("getPermittedAccessibilityServices");
if (mService != null) {
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index b2fe958..85f4efc 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -305,6 +305,8 @@
* {@link java.lang.System#currentTimeMillis}.
* @param uid UID of app
* @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
+ * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
+ * traffic from all states.
* @return Statistics object or null if an error happened during statistics collection.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index af99bf7..3bc8544 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -701,6 +701,28 @@
}
/**
+ * Gets the application name of the current HidDeviceService user.
+ *
+ * @return the current user name, or empty string if cannot get the name
+ * {@hide}
+ */
+ public String getUserAppName() {
+ final IBluetoothHidDevice service = mService;
+
+ if (service != null) {
+ try {
+ return service.getUserAppName();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return "";
+ }
+
+ /**
* Initiates connection to host which is currently paired with this device. If the application
* is not registered, #connect(BluetoothDevice) will fail. The connection state should be
* tracked by the application by handling callback from Callback#onConnectionStateChanged. The
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9f3df37..f7908b6 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -51,7 +51,6 @@
import android.util.EventLog;
import android.util.Log;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.MimeIconUtils;
import com.android.internal.util.Preconditions;
@@ -602,6 +601,8 @@
try {
return provider.getType(url);
} catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
return null;
} catch (java.lang.Exception e) {
Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
@@ -620,9 +621,7 @@
ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
return type;
} catch (RemoteException e) {
- // Arbitrary and not worth documenting, as Activity
- // Manager will kill this process shortly anyway.
- return null;
+ throw e.rethrowFromSystemServer();
} catch (java.lang.Exception e) {
Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
return null;
@@ -1964,6 +1963,7 @@
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1982,6 +1982,7 @@
contentObserver);
}
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2089,6 +2090,7 @@
syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2105,6 +2107,7 @@
observer != null && observer.deliverSelfNotifications(), flags,
userHandle, mTargetSdkVersion);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2126,6 +2129,7 @@
ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
resolveUserId(uri));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2141,6 +2145,7 @@
ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
resolveUserId(uri));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2160,6 +2165,7 @@
ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
resolveUserId(uri));
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2178,7 +2184,7 @@
return ActivityManager.getService()
.getPersistedUriPermissions(mPackageName, true).getList();
} catch (RemoteException e) {
- throw new RuntimeException("Activity manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2194,7 +2200,7 @@
return ActivityManager.getService()
.getPersistedUriPermissions(mPackageName, false).getList();
} catch (RemoteException e) {
- throw new RuntimeException("Activity manager has died", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2273,7 +2279,7 @@
try {
getContentService().syncAsUser(request, userId);
} catch(RemoteException e) {
- // Shouldn't happen.
+ throw e.rethrowFromSystemServer();
}
}
@@ -2285,7 +2291,7 @@
try {
getContentService().sync(request);
} catch(RemoteException e) {
- // Shouldn't happen.
+ throw e.rethrowFromSystemServer();
}
}
@@ -2349,6 +2355,7 @@
try {
getContentService().cancelSync(account, authority, null);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2360,6 +2367,7 @@
try {
getContentService().cancelSyncAsUser(account, authority, null, userId);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2371,7 +2379,7 @@
try {
return getContentService().getSyncAdapterTypes();
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2383,7 +2391,7 @@
try {
return getContentService().getSyncAdapterTypesAsUser(userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2397,8 +2405,8 @@
try {
return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return ArrayUtils.emptyArray(String.class);
}
/**
@@ -2414,7 +2422,7 @@
try {
return getContentService().getSyncAutomatically(account, authority);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2427,7 +2435,7 @@
try {
return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2453,8 +2461,7 @@
try {
getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -2500,8 +2507,7 @@
try {
getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -2540,7 +2546,7 @@
try {
getContentService().removePeriodicSync(account, authority, extras);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2564,8 +2570,7 @@
try {
getContentService().cancelRequest(request);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -2582,7 +2587,7 @@
try {
return getContentService().getPeriodicSyncs(account, authority, null);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2596,7 +2601,7 @@
try {
return getContentService().getIsSyncable(account, authority);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2609,7 +2614,7 @@
try {
return getContentService().getIsSyncableAsUser(account, authority, userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2623,8 +2628,7 @@
try {
getContentService().setIsSyncable(account, authority, syncable);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -2640,7 +2644,7 @@
try {
return getContentService().getMasterSyncAutomatically();
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2652,7 +2656,7 @@
try {
return getContentService().getMasterSyncAutomaticallyAsUser(userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2676,8 +2680,7 @@
try {
getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -2701,7 +2704,7 @@
try {
return getContentService().isSyncActive(account, authority, null);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2727,7 +2730,7 @@
}
return syncs.get(0);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2744,7 +2747,7 @@
try {
return getContentService().getCurrentSyncs();
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2756,7 +2759,7 @@
try {
return getContentService().getCurrentSyncsAsUser(userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2771,7 +2774,7 @@
try {
return getContentService().getSyncStatus(account, authority, null);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2784,7 +2787,7 @@
try {
return getContentService().getSyncStatusAsUser(account, authority, null, userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2809,7 +2812,7 @@
try {
return getContentService().isSyncPendingAsUser(account, authority, null, userId);
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2841,7 +2844,7 @@
getContentService().addStatusChangeListener(mask, observer);
return observer;
} catch (RemoteException e) {
- throw new RuntimeException("the ContentService should always be reachable", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -2856,8 +2859,7 @@
try {
getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
} catch (RemoteException e) {
- // exception ignored; if this is thrown then it means the runtime is in the midst of
- // being restarted
+ throw e.rethrowFromSystemServer();
}
}
@@ -3027,9 +3029,7 @@
return sContentService;
}
IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
- if (false) Log.v("ContentService", "default service binder = " + b);
sContentService = IContentService.Stub.asInterface(b);
- if (false) Log.v("ContentService", "default service = " + sContentService);
return sContentService;
}
@@ -3038,7 +3038,7 @@
return mPackageName;
}
- private static IContentService sContentService;
+ private static volatile IContentService sContentService;
private final Context mContext;
final String mPackageName;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 920056a..ede7ee4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3780,7 +3780,7 @@
public static final String DROPBOX_SERVICE = "dropbox";
/**
- * System service name for the DeviceIdleController. There is no Java API for this.
+ * System service name for the DeviceIdleManager.
* @see #getSystemService(String)
* @hide
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index efc9b6d..01ee671 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6810,6 +6810,9 @@
case "--activity-task-on-home":
intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
break;
+ case "--activity-match-external":
+ intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
+ break;
case "--receiver-registered-only":
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
break;
@@ -6946,7 +6949,7 @@
" [--activity-no-user-action] [--activity-previous-is-top]",
" [--activity-reorder-to-front] [--activity-reset-task-if-needed]",
" [--activity-single-top] [--activity-clear-task]",
- " [--activity-task-on-home]",
+ " [--activity-task-on-home] [--activity-match-external]",
" [--receiver-registered-only] [--receiver-replace-pending]",
" [--receiver-foreground] [--receiver-no-abort]",
" [--receiver-include-background]",
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 660026f..d734aa3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3952,6 +3952,7 @@
*
* @hide
*/
+ @TestApi
public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
/**
@@ -3961,6 +3962,7 @@
*
* @hide
*/
+ @TestApi
public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
/**
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 82af5d3..6f812ac 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -233,6 +233,8 @@
*
* @param capability The capability to add to unwanted capability list.
* @return The builder to facilitate chaining.
+ *
+ * @removed
*/
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addUnwantedCapability(capability);
@@ -439,6 +441,8 @@
/**
* @see Builder#addUnwantedCapability(int)
+ *
+ * @removed
*/
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index 3b0dc7e..76a781d 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -20,7 +20,7 @@
import android.os.Parcelable;
/**
- * An event logged for an interface with APF capabilities when its IpManager state machine exits.
+ * An event logged for an interface with APF capabilities when its IpClient state machine exits.
* {@hide}
*/
public final class ApfStats implements Parcelable {
diff --git a/core/java/android/os/DeviceIdleManager.java b/core/java/android/os/DeviceIdleManager.java
new file mode 100644
index 0000000..9039f92
--- /dev/null
+++ b/core/java/android/os/DeviceIdleManager.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.annotation.TestApi;
+import android.content.Context;
+
+/**
+ * Access to the service that keeps track of device idleness and drives low power mode based on
+ * that.
+ *
+ * @hide
+ */
+@TestApi
+@SystemService(Context.DEVICE_IDLE_CONTROLLER)
+public class DeviceIdleManager {
+ private final Context mContext;
+ private final IDeviceIdleController mService;
+
+ /**
+ * @hide
+ */
+ public DeviceIdleManager(@NonNull Context context, @NonNull IDeviceIdleController service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * @return package names the system has white-listed to opt out of power save restrictions,
+ * except for device idle mode.
+ */
+ public @NonNull String[] getSystemPowerWhitelistExceptIdle() {
+ try {
+ return mService.getSystemPowerWhitelistExceptIdle();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return new String[0];
+ }
+ }
+
+ /**
+ * @return package names the system has white-listed to opt out of power save restrictions for
+ * all modes.
+ */
+ public @NonNull String[] getSystemPowerWhitelist() {
+ try {
+ return mService.getSystemPowerWhitelist();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return new String[0];
+ }
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 03203d0..213260f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.TestApi;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.storage.StorageManager;
@@ -1033,6 +1034,7 @@
*
* @hide
*/
+ @TestApi
public static File buildPath(File base, String... segments) {
File cur = base;
for (String segment : segments) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 8eb39c0..7d3ba6a 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.util.Log;
import android.util.MutableInt;
@@ -35,6 +36,7 @@
* {@hide}
*/
@SystemApi
+@TestApi
public class SystemProperties {
private static final String TAG = "SystemProperties";
private static final boolean TRACK_KEY_ACCESS = false;
@@ -110,6 +112,7 @@
*/
@NonNull
@SystemApi
+ @TestApi
public static String get(@NonNull String key, @Nullable String def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 094f004..4d4f31d 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -82,6 +82,7 @@
public static final int USER_SERIAL_SYSTEM = 0;
/** @hide A user handle to indicate the "system" user of the device */
+ @TestApi
public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 54bbb7d..5e4d191 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1153,6 +1153,7 @@
* primary user are two separate users. Previously system user and primary user are combined as
* a single owner user. see @link {android.os.UserHandle#USER_OWNER}
*/
+ @TestApi
public static boolean isSplitSystemUser() {
return RoSystemProperties.FW_SYSTEM_USER_SPLIT;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5a3cf77..b644c1d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5313,7 +5313,7 @@
*
* For more information about how the platform handles {@code ANDROID_ID}
* in Android 8.0 (API level 26) and higher, see <a
- * href="{@docRoot}preview/behavior-changes.html#privacy-all">
+ * href="{@docRoot}about/versions/oreo/android-8.0-changes.html#privacy-all">
* Android 8.0 Behavior Changes</a>.
*
* <p class="note"><strong>Note:</strong> For apps that were installed
@@ -7384,6 +7384,17 @@
BOOLEAN_VALIDATOR;
/**
+ * Whether the swipe up gesture to switch apps should be enabled.
+ *
+ * @hide
+ */
+ public static final String SWIPE_UP_TO_SWITCH_APPS_ENABLED =
+ "swipe_up_to_switch_apps_enabled";
+
+ private static final Validator SWIPE_UP_TO_SWITCH_APPS_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
+ /**
* Whether or not the smart camera lift trigger that launches the camera when the user moves
* the phone into a position for taking photos should be enabled.
*
@@ -7894,6 +7905,7 @@
NIGHT_DISPLAY_AUTO_MODE,
SYNC_PARENT_SOUNDS,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+ SWIPE_UP_TO_SWITCH_APPS_ENABLED,
CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
SYSTEM_NAVIGATION_KEYS_ENABLED,
QS_TILES,
@@ -8027,6 +8039,8 @@
VALIDATORS.put(SYNC_PARENT_SOUNDS, SYNC_PARENT_SOUNDS_VALIDATOR);
VALIDATORS.put(CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR);
+ VALIDATORS.put(SWIPE_UP_TO_SWITCH_APPS_ENABLED,
+ SWIPE_UP_TO_SWITCH_APPS_ENABLED_VALIDATOR);
VALIDATORS.put(CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED_VALIDATOR);
VALIDATORS.put(SYSTEM_NAVIGATION_KEYS_ENABLED,
@@ -8938,6 +8952,20 @@
/** {@hide} */
public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
+ /** {@hide} */
+ public static final String NETPOLICY_QUOTA_ENABLED = "netpolicy_quota_enabled";
+ /** {@hide} */
+ public static final String NETPOLICY_QUOTA_UNLIMITED = "netpolicy_quota_unlimited";
+ /** {@hide} */
+ public static final String NETPOLICY_QUOTA_LIMITED = "netpolicy_quota_limited";
+ /** {@hide} */
+ public static final String NETPOLICY_QUOTA_FRAC_JOBS = "netpolicy_quota_frac_jobs";
+ /** {@hide} */
+ public static final String NETPOLICY_QUOTA_FRAC_MULTIPATH = "netpolicy_quota_frac_multipath";
+
+ /** {@hide} */
+ public static final String NETPOLICY_OVERRIDE_ENABLED = "netpolicy_override_enabled";
+
/**
* User preference for which network(s) should be used. Only the
* connectivity service should touch this.
@@ -10809,6 +10837,15 @@
= "time_only_mode_constants";
/**
+ * Whether of not to send keycode sleep for ungaze when Home is the foreground activity on
+ * watch type devices.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String UNGAZE_SLEEP_ENABLED = "ungaze_sleep_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/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 3830b7a..daecea7 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1487,14 +1487,18 @@
/**
* Returns a description of the current do not disturb settings from config.
* - If turned on manually and end time is known, returns end time.
+ * - If turned on manually and end time is on forever until turned off, return null if
+ * describeForeverCondition is false, else return String describing indefinite behavior
* - If turned on by an automatic rule, returns the automatic rule name.
* - If on due to an app, returns the app name.
* - If there's a combination of rules/apps that trigger, then shows the one that will
* last the longest if applicable.
- * @return null if do not disturb is off.
+ * @return null if DND is off or describeForeverCondition is false and
+ * DND is on forever (until turned off)
*/
- public static String getDescription(Context context, boolean zenOn, ZenModeConfig config) {
- if (!zenOn) {
+ public static String getDescription(Context context, boolean zenOn, ZenModeConfig config,
+ boolean describeForeverCondition) {
+ if (!zenOn || config == null) {
return null;
}
@@ -1513,8 +1517,11 @@
} else {
if (id == null) {
// Do not disturb manually triggered to remain on forever until turned off
- // No subtext
- return null;
+ if (describeForeverCondition) {
+ return context.getString(R.string.zen_mode_forever);
+ } else {
+ return null;
+ }
} else {
latestEndTime = tryParseCountdownConditionId(id);
if (latestEndTime > 0) {
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index 3445658..5256e47 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -180,7 +180,7 @@
* Remove the selection or cursor, if any, from the text.
*/
public static final void removeSelection(Spannable text) {
- text.removeSpan(SELECTION_START);
+ text.removeSpan(SELECTION_START, Spanned.SPAN_INTERMEDIATE);
text.removeSpan(SELECTION_END);
removeMemory(text);
}
diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java
index 39b78eb..8315b2a 100644
--- a/core/java/android/text/Spannable.java
+++ b/core/java/android/text/Spannable.java
@@ -46,6 +46,19 @@
public void removeSpan(Object what);
/**
+ * Remove the specified object from the range of text to which it
+ * was attached, if any. It is OK to remove an object that was never
+ * attached in the first place.
+ *
+ * See {@link Spanned} for an explanation of what the flags mean.
+ *
+ * @hide
+ */
+ default void removeSpan(Object what, int flags) {
+ removeSpan(what);
+ }
+
+ /**
* Factory used by TextView to create new {@link Spannable Spannables}. You can subclass
* it to provide something other than {@link SpannableString}.
*
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index d41dfdc..41a9c45 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -312,7 +312,7 @@
// The following condition indicates that the span would become empty
(textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
mIndexOfSpan.remove(mSpans[i]);
- removeSpan(i);
+ removeSpan(i, 0 /* flags */);
return true;
}
return resolveGap(mSpanStarts[i]) <= end && (i & 1) != 0 &&
@@ -472,7 +472,7 @@
}
// Note: caller is responsible for removing the mIndexOfSpan entry.
- private void removeSpan(int i) {
+ private void removeSpan(int i, int flags) {
Object object = mSpans[i];
int start = mSpanStarts[i];
@@ -496,7 +496,9 @@
// Invariants must be restored before sending span removed notifications.
restoreInvariants();
- sendSpanRemoved(object, start, end);
+ if ((flags & Spanned.SPAN_INTERMEDIATE) == 0) {
+ sendSpanRemoved(object, start, end);
+ }
}
// Documentation from interface
@@ -782,10 +784,19 @@
* Remove the specified markup object from the buffer.
*/
public void removeSpan(Object what) {
+ removeSpan(what, 0 /* flags */);
+ }
+
+ /**
+ * Remove the specified markup object from the buffer.
+ *
+ * @hide
+ */
+ public void removeSpan(Object what, int flags) {
if (mIndexOfSpan == null) return;
Integer i = mIndexOfSpan.remove(what);
if (i != null) {
- removeSpan(i.intValue());
+ removeSpan(i.intValue(), flags);
}
}
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 5dd1a52..bcc2fda 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -249,6 +249,13 @@
}
/* package */ void removeSpan(Object what) {
+ removeSpan(what, 0 /* flags */);
+ }
+
+ /**
+ * @hide
+ */
+ public void removeSpan(Object what, int flags) {
int count = mSpanCount;
Object[] spans = mSpans;
int[] data = mSpanData;
@@ -262,11 +269,13 @@
System.arraycopy(spans, i + 1, spans, i, c);
System.arraycopy(data, (i + 1) * COLUMNS,
- data, i * COLUMNS, c * COLUMNS);
+ data, i * COLUMNS, c * COLUMNS);
mSpanCount--;
- sendSpanRemoved(what, ostart, oend);
+ if ((flags & Spanned.SPAN_INTERMEDIATE) == 0) {
+ sendSpanRemoved(what, ostart, oend);
+ }
return;
}
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index eecdb74..59387d6 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,7 +38,6 @@
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
- DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d4610a5..5deee11 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -87,6 +87,7 @@
private static native void nativeMergeTransaction(long transactionObj,
long otherTransactionObj);
private static native void nativeSetAnimationTransaction(long transactionObj);
+ private static native void nativeSetEarlyWakeup(long transactionObj);
private static native void nativeSetLayer(long transactionObj, long nativeObject, int zorder);
private static native void nativeSetRelativeLayer(long transactionObj, long nativeObject,
@@ -1642,6 +1643,19 @@
}
/**
+ * Indicate that SurfaceFlinger should wake up earlier than usual as a result of this
+ * transaction. This should be used when the caller thinks that the scene is complex enough
+ * that it's likely to hit GL composition, and thus, SurfaceFlinger needs to more time in
+ * order not to miss frame deadlines.
+ * <p>
+ * Corresponds to setting ISurfaceComposer::eEarlyWakeup
+ */
+ public Transaction setEarlyWakeup() {
+ nativeSetEarlyWakeup(mNativeObject);
+ return this;
+ }
+
+ /**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
*/
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 9b49248..a6495d1 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -79,9 +79,8 @@
public AutofillPopupWindow(@NonNull IAutofillWindowPresenter presenter) {
mWindowPresenter = new WindowPresenter(presenter);
- // Here is a bit of voodoo - we want to show the window as system
- // controlled one so it covers app windows, but at the same time it has to be
- // an application type (so it's contained inside the application area).
+ // We want to show the window as system controlled one so it covers app windows, but it has
+ // to be an application type (so it's contained inside the application area).
// Hence, we set it to the application type with the highest z-order, which currently
// is TYPE_APPLICATION_ABOVE_SUB_PANEL.
setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 5f7a0f7..090e19f 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -522,7 +522,7 @@
b = tmp;
}
- if (a == b) return null;
+ if (a == b || a < 0) return null;
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
return content.subSequence(a, b);
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index f0f30a0..372362f 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -503,6 +503,14 @@
/**
* @hide
+ * @return {@code true} if the IME is a trusted system component (e.g. pre-installed)
+ */
+ public boolean isSystem() {
+ return (mService.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ /**
+ * @hide
*/
public boolean isAuxiliaryIme() {
return mIsAuxIme;
diff --git a/core/java/android/view/textclassifier/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
index 73cf43b..067513f 100644
--- a/core/java/android/view/textclassifier/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -19,13 +19,13 @@
import android.annotation.Nullable;
import android.metrics.LogMaker;
import android.util.ArrayMap;
-import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@@ -39,6 +39,7 @@
public final class GenerateLinksLogger {
private static final String LOG_TAG = "GenerateLinksLogger";
+ private static final boolean DEBUG_LOG_ENABLED = false;
private static final String ZERO = "0";
private final MetricsLogger mMetricsLogger;
@@ -127,7 +128,7 @@
}
private static void debugLog(LogMaker log) {
- if (!Logger.DEBUG_LOG_ENABLED) return;
+ if (!DEBUG_LOG_ENABLED) return;
final String callId = Objects.toString(
log.getTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID), "");
@@ -142,8 +143,9 @@
final int latencyMs = Integer.parseInt(
Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_LATENCY), ZERO));
- Log.d(LOG_TAG, String.format("%s:%s %d links (%d/%d chars) %dms %s", callId, entityType,
- numLinks, linkLength, textLength, latencyMs, log.getPackageName()));
+ Log.d(LOG_TAG,
+ String.format(Locale.US, "%s:%s %d links (%d/%d chars) %dms %s", callId, entityType,
+ numLinks, linkLength, textLength, latencyMs, log.getPackageName()));
}
/** Helper class for storing per-entity type statistics. */
diff --git a/core/java/android/view/textclassifier/Logger.java b/core/java/android/view/textclassifier/Logger.java
deleted file mode 100644
index f03906a..0000000
--- a/core/java/android/view/textclassifier/Logger.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.textclassifier;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-
-import com.android.internal.util.Preconditions;
-
-import java.text.BreakIterator;
-import java.util.Locale;
-import java.util.Objects;
-
-/**
- * A helper for logging TextClassifier related events.
- * @hide
- */
-public abstract class Logger {
-
- private static final String LOG_TAG = "Logger";
- /* package */ static final boolean DEBUG_LOG_ENABLED = true;
-
- private @SelectionEvent.InvocationMethod int mInvocationMethod;
- private SelectionEvent mPrevEvent;
- private SelectionEvent mSmartEvent;
- private SelectionEvent mStartEvent;
-
- /**
- * Logger that does not log anything.
- * @hide
- */
- public static final Logger DISABLED = new Logger() {
- @Override
- public void writeEvent(SelectionEvent event) {}
- };
-
- @Nullable
- private final Config mConfig;
-
- public Logger(Config config) {
- mConfig = Preconditions.checkNotNull(config);
- }
-
- private Logger() {
- mConfig = null;
- }
-
- /**
- * Writes the selection event to a log.
- */
- public abstract void writeEvent(@NonNull SelectionEvent event);
-
- /**
- * Returns true if the resultId matches that of a smart selection event (i.e.
- * {@link SelectionEvent#EVENT_SMART_SELECTION_SINGLE} or
- * {@link SelectionEvent#EVENT_SMART_SELECTION_MULTI}).
- * Returns false otherwise.
- */
- public boolean isSmartSelection(@NonNull String resultId) {
- return false;
- }
-
- /**
- * Returns a token iterator for tokenizing text for logging purposes.
- */
- public BreakIterator getTokenIterator(@NonNull Locale locale) {
- return BreakIterator.getWordInstance(Preconditions.checkNotNull(locale));
- }
-
- /**
- * Logs a "selection started" event.
- *
- * @param invocationMethod the way the selection was triggered
- * @param start the token index of the selected token
- */
- public final void logSelectionStartedEvent(
- @SelectionEvent.InvocationMethod int invocationMethod, int start) {
- if (mConfig == null) {
- return;
- }
-
- mInvocationMethod = invocationMethod;
- logEvent(new SelectionEvent(
- start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED,
- TextClassifier.TYPE_UNKNOWN, mInvocationMethod, null, mConfig));
- }
-
- /**
- * Logs a "selection modified" event.
- * Use when the user modifies the selection.
- *
- * @param start the start token (inclusive) index of the selection
- * @param end the end token (exclusive) index of the selection
- */
- public final void logSelectionModifiedEvent(int start, int end) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
-
- if (mConfig == null) {
- return;
- }
-
- logEvent(new SelectionEvent(
- start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
- TextClassifier.TYPE_UNKNOWN, mInvocationMethod, null, mConfig));
- }
-
- /**
- * Logs a "selection modified" event.
- * Use when the user modifies the selection and the selection's entity type is known.
- *
- * @param start the start token (inclusive) index of the selection
- * @param end the end token (exclusive) index of the selection
- * @param classification the TextClassification object returned by the TextClassifier that
- * classified the selected text
- */
- public final void logSelectionModifiedEvent(
- int start, int end, @NonNull TextClassification classification) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
- Preconditions.checkNotNull(classification);
-
- if (mConfig == null) {
- return;
- }
-
- final String entityType = classification.getEntityCount() > 0
- ? classification.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- logEvent(new SelectionEvent(
- start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
- entityType, mInvocationMethod, classification.getId(), mConfig));
- }
-
- /**
- * Logs a "selection modified" event.
- * Use when a TextClassifier modifies the selection.
- *
- * @param start the start token (inclusive) index of the selection
- * @param end the end token (exclusive) index of the selection
- * @param selection the TextSelection object returned by the TextClassifier for the
- * specified selection
- */
- public final void logSelectionModifiedEvent(
- int start, int end, @NonNull TextSelection selection) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
- Preconditions.checkNotNull(selection);
-
- if (mConfig == null) {
- return;
- }
-
- final int eventType;
- if (isSmartSelection(selection.getId())) {
- eventType = end - start > 1
- ? SelectionEvent.EVENT_SMART_SELECTION_MULTI
- : SelectionEvent.EVENT_SMART_SELECTION_SINGLE;
-
- } else {
- eventType = SelectionEvent.EVENT_AUTO_SELECTION;
- }
- final String entityType = selection.getEntityCount() > 0
- ? selection.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- logEvent(new SelectionEvent(start, end, eventType, entityType, mInvocationMethod,
- selection.getId(), mConfig));
- }
-
- /**
- * Logs an event specifying an action taken on a selection.
- * Use when the user clicks on an action to act on the selected text.
- *
- * @param start the start token (inclusive) index of the selection
- * @param end the end token (exclusive) index of the selection
- * @param actionType the action that was performed on the selection
- */
- public final void logSelectionActionEvent(
- int start, int end, @SelectionEvent.ActionType int actionType) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
- checkActionType(actionType);
-
- if (mConfig == null) {
- return;
- }
-
- logEvent(new SelectionEvent(
- start, end, actionType, TextClassifier.TYPE_UNKNOWN, mInvocationMethod,
- null, mConfig));
- }
-
- /**
- * Logs an event specifying an action taken on a selection.
- * Use when the user clicks on an action to act on the selected text and the selection's
- * entity type is known.
- *
- * @param start the start token (inclusive) index of the selection
- * @param end the end token (exclusive) index of the selection
- * @param actionType the action that was performed on the selection
- * @param classification the TextClassification object returned by the TextClassifier that
- * classified the selected text
- *
- * @throws IllegalArgumentException If actionType is not a valid SelectionEvent actionType
- */
- public final void logSelectionActionEvent(
- int start, int end, @SelectionEvent.ActionType int actionType,
- @NonNull TextClassification classification) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
- Preconditions.checkNotNull(classification);
- checkActionType(actionType);
-
- if (mConfig == null) {
- return;
- }
-
- final String entityType = classification.getEntityCount() > 0
- ? classification.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- logEvent(new SelectionEvent(start, end, actionType, entityType, mInvocationMethod,
- classification.getId(), mConfig));
- }
-
- private void logEvent(@NonNull SelectionEvent event) {
- Preconditions.checkNotNull(event);
-
- if (event.getEventType() != SelectionEvent.EVENT_SELECTION_STARTED
- && mStartEvent == null) {
- if (DEBUG_LOG_ENABLED) {
- Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
- }
- return;
- }
-
- final long now = System.currentTimeMillis();
- switch (event.getEventType()) {
- case SelectionEvent.EVENT_SELECTION_STARTED:
- Preconditions.checkArgument(event.getAbsoluteEnd() == event.getAbsoluteStart() + 1);
- event.setSessionId(startNewSession());
- mStartEvent = event;
- break;
- case SelectionEvent.EVENT_SMART_SELECTION_SINGLE: // fall through
- case SelectionEvent.EVENT_SMART_SELECTION_MULTI:
- mSmartEvent = event;
- break;
- case SelectionEvent.EVENT_SELECTION_MODIFIED: // fall through
- case SelectionEvent.EVENT_AUTO_SELECTION:
- if (mPrevEvent != null
- && mPrevEvent.getAbsoluteStart() == event.getAbsoluteStart()
- && mPrevEvent.getAbsoluteEnd() == event.getAbsoluteEnd()) {
- // Selection did not change. Ignore event.
- return;
- }
- break;
- default:
- // do nothing.
- }
-
- event.setEventTime(now);
- if (mStartEvent != null) {
- event.setSessionId(mStartEvent.getSessionId())
- .setDurationSinceSessionStart(now - mStartEvent.getEventTime())
- .setStart(event.getAbsoluteStart() - mStartEvent.getAbsoluteStart())
- .setEnd(event.getAbsoluteEnd() - mStartEvent.getAbsoluteStart());
- }
- if (mSmartEvent != null) {
- event.setResultId(mSmartEvent.getResultId())
- .setSmartStart(mSmartEvent.getAbsoluteStart() - mStartEvent.getAbsoluteStart())
- .setSmartEnd(mSmartEvent.getAbsoluteEnd() - mStartEvent.getAbsoluteStart());
- }
- if (mPrevEvent != null) {
- event.setDurationSincePreviousEvent(now - mPrevEvent.getEventTime())
- .setEventIndex(mPrevEvent.getEventIndex() + 1);
- }
- writeEvent(event);
- mPrevEvent = event;
-
- if (event.isTerminal()) {
- endSession();
- }
- }
-
- private TextClassificationSessionId startNewSession() {
- endSession();
- return new TextClassificationSessionId();
- }
-
- private void endSession() {
- mPrevEvent = null;
- mSmartEvent = null;
- mStartEvent = null;
- }
-
- /**
- * @throws IllegalArgumentException If eventType is not an {@link SelectionEvent.ActionType}
- */
- private static void checkActionType(@SelectionEvent.EventType int eventType)
- throws IllegalArgumentException {
- switch (eventType) {
- case SelectionEvent.ACTION_OVERTYPE: // fall through
- case SelectionEvent.ACTION_COPY: // fall through
- case SelectionEvent.ACTION_PASTE: // fall through
- case SelectionEvent.ACTION_CUT: // fall through
- case SelectionEvent.ACTION_SHARE: // fall through
- case SelectionEvent.ACTION_SMART_SHARE: // fall through
- case SelectionEvent.ACTION_DRAG: // fall through
- case SelectionEvent.ACTION_ABANDON: // fall through
- case SelectionEvent.ACTION_SELECT_ALL: // fall through
- case SelectionEvent.ACTION_RESET: // fall through
- return;
- default:
- throw new IllegalArgumentException(
- String.format(Locale.US, "%d is not an eventType", eventType));
- }
- }
-
-
- /**
- * A Logger config.
- */
- public static final class Config {
-
- private final String mPackageName;
- private final String mWidgetType;
- @Nullable private final String mWidgetVersion;
-
- /**
- * @param context Context of the widget the logger logs for
- * @param widgetType a name for the widget being logged for. e.g.
- * {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}
- * @param widgetVersion a string version info for the widget the logger logs for
- */
- public Config(
- @NonNull Context context,
- @TextClassifier.WidgetType String widgetType,
- @Nullable String widgetVersion) {
- mPackageName = Preconditions.checkNotNull(context).getPackageName();
- mWidgetType = widgetType;
- mWidgetVersion = widgetVersion;
- }
-
- /**
- * Returns the package name of the application the logger logs for.
- */
- public String getPackageName() {
- return mPackageName;
- }
-
- /**
- * Returns the name for the widget being logged for. e.g.
- * {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}.
- */
- public String getWidgetType() {
- return mWidgetType;
- }
-
- /**
- * Returns string version info for the logger. This is specific to the text classifier.
- */
- @Nullable
- public String getWidgetVersion() {
- return mWidgetVersion;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mPackageName, mWidgetType, mWidgetVersion);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (!(obj instanceof Config)) {
- return false;
- }
-
- final Config other = (Config) obj;
- return Objects.equals(mPackageName, other.mPackageName)
- && Objects.equals(mWidgetType, other.mWidgetType)
- && Objects.equals(mWidgetVersion, other.mWidgetType);
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 1e978cc..b073596 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -150,20 +150,6 @@
mInvocationMethod = invocationMethod;
}
- SelectionEvent(
- int start, int end,
- @EventType int eventType, @EntityType String entityType,
- @InvocationMethod int invocationMethod, @Nullable String resultId,
- Logger.Config config) {
- this(start, end, eventType, entityType, invocationMethod, resultId);
- Preconditions.checkNotNull(config);
- setTextClassificationSessionContext(
- new TextClassificationContext.Builder(
- config.getPackageName(), config.getWidgetType())
- .setWidgetVersion(config.getWidgetVersion())
- .build());
- }
-
private SelectionEvent(Parcel in) {
mAbsoluteStart = in.readInt();
mAbsoluteEnd = in.readInt();
@@ -362,6 +348,7 @@
case SelectionEvent.ACTION_ABANDON: // fall through
case SelectionEvent.ACTION_SELECT_ALL: // fall through
case SelectionEvent.ACTION_RESET: // fall through
+ case SelectionEvent.ACTION_OTHER: // fall through
return;
default:
throw new IllegalArgumentException(
@@ -667,4 +654,4 @@
return new SelectionEvent[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/textclassifier/DefaultLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java
similarity index 88%
rename from core/java/android/view/textclassifier/DefaultLogger.java
rename to core/java/android/view/textclassifier/SelectionSessionLogger.java
index 203ca56..f2fb63e 100644
--- a/core/java/android/view/textclassifier/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java
@@ -17,28 +17,29 @@
package android.view.textclassifier;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.metrics.LogMaker;
-import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
+import java.text.BreakIterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.StringJoiner;
/**
- * Default Logger.
- * Used internally by TextClassifierImpl.
+ * A helper for logging selection session events.
* @hide
*/
-public final class DefaultLogger extends Logger {
+public final class SelectionSessionLogger {
- private static final String LOG_TAG = "DefaultLogger";
+ private static final String LOG_TAG = "SelectionSessionLogger";
+ private static final boolean DEBUG_LOG_ENABLED = false;
static final String CLASSIFIER_ID = "androidtc";
private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
@@ -59,23 +60,16 @@
private final MetricsLogger mMetricsLogger;
- public DefaultLogger(@NonNull Config config) {
- super(config);
+ public SelectionSessionLogger() {
mMetricsLogger = new MetricsLogger();
}
@VisibleForTesting
- public DefaultLogger(@NonNull Config config, @NonNull MetricsLogger metricsLogger) {
- super(config);
+ public SelectionSessionLogger(@NonNull MetricsLogger metricsLogger) {
mMetricsLogger = Preconditions.checkNotNull(metricsLogger);
}
- @Override
- public boolean isSmartSelection(@NonNull String signature) {
- return CLASSIFIER_ID.equals(SignatureParser.getClassifierId(signature));
- }
-
- @Override
+ /** Emits a selection event to the logs. */
public void writeEvent(@NonNull SelectionEvent event) {
Preconditions.checkNotNull(event);
final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
@@ -93,7 +87,7 @@
.addTaggedData(SMART_END, event.getSmartEnd())
.addTaggedData(EVENT_START, event.getStart())
.addTaggedData(EVENT_END, event.getEnd())
- .addTaggedData(SESSION_ID, event.getSessionId());
+ .addTaggedData(SESSION_ID, event.getSessionId().flattenToString());
mMetricsLogger.write(log);
debugLog(log);
}
@@ -225,9 +219,17 @@
final int eventEnd = Integer.parseInt(
Objects.toString(log.getTaggedData(EVENT_END), ZERO));
- Log.d(LOG_TAG, String.format("%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
- index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd, widget,
- model));
+ Log.d(LOG_TAG,
+ String.format(Locale.US, "%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
+ index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd,
+ widget, model));
+ }
+
+ /**
+ * Returns a token iterator for tokenizing text for logging purposes.
+ */
+ public static BreakIterator getTokenIterator(@NonNull Locale locale) {
+ return BreakIterator.getWordInstance(Preconditions.checkNotNull(locale));
}
/**
@@ -260,8 +262,10 @@
return String.format(Locale.US, "%s|%s|%d", classifierId, modelName, hash);
}
- static String getClassifierId(String signature) {
- Preconditions.checkNotNull(signature);
+ static String getClassifierId(@Nullable String signature) {
+ if (signature == null) {
+ return "";
+ }
final int end = signature.indexOf("|");
if (end >= 0) {
return signature.substring(0, end);
@@ -269,8 +273,10 @@
return "";
}
- static String getModelName(String signature) {
- Preconditions.checkNotNull(signature);
+ static String getModelName(@Nullable String signature) {
+ if (signature == null) {
+ return "";
+ }
final int start = signature.indexOf("|") + 1;
final int end = signature.indexOf("|", start);
if (start >= 1 && end >= start) {
@@ -279,8 +285,10 @@
return "";
}
- static int getHash(String signature) {
- Preconditions.checkNotNull(signature);
+ static int getHash(@Nullable String signature) {
+ if (signature == null) {
+ return 0;
+ }
final int index1 = signature.indexOf("|");
final int index2 = signature.indexOf("|", index1);
if (index2 > 0) {
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 45fd6bf..490c389 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -28,7 +28,6 @@
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.Preconditions;
@@ -49,13 +48,6 @@
private final TextClassificationConstants mSettings;
private final TextClassifier mFallback;
private final String mPackageName;
-
- private final Object mLoggerLock = new Object();
- @GuardedBy("mLoggerLock")
- private Logger.Config mLoggerConfig;
- @GuardedBy("mLoggerLock")
- private Logger mLogger;
- @GuardedBy("mLoggerLock")
private TextClassificationSessionId mSessionId;
public SystemTextClassifier(Context context, TextClassificationConstants settings)
@@ -147,27 +139,6 @@
}
@Override
- public Logger getLogger(@NonNull Logger.Config config) {
- Preconditions.checkNotNull(config);
- synchronized (mLoggerLock) {
- if (mLogger == null || !config.equals(mLoggerConfig)) {
- mLoggerConfig = config;
- mLogger = new Logger(config) {
- @Override
- public void writeEvent(SelectionEvent event) {
- try {
- mManagerService.onSelectionEvent(mSessionId, event);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error reporting selection event.", e);
- }
- }
- };
- }
- }
- return mLogger;
- }
-
- @Override
public void destroy() {
try {
if (mSessionId != null) {
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index e8e300a..4c64198 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -17,7 +17,6 @@
package android.view.textclassifier;
import android.annotation.WorkerThread;
-import android.view.textclassifier.DefaultLogger.SignatureParser;
import android.view.textclassifier.SelectionEvent.InvocationMethod;
import com.android.internal.util.Preconditions;
@@ -222,7 +221,8 @@
}
private static boolean isPlatformLocalTextClassifierSmartSelection(String signature) {
- return DefaultLogger.CLASSIFIER_ID.equals(SignatureParser.getClassifierId(signature));
+ return SelectionSessionLogger.CLASSIFIER_ID.equals(
+ SelectionSessionLogger.SignatureParser.getClassifierId(signature));
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index f048d29..da47bcb 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -359,18 +359,6 @@
}
/**
- * Returns a helper for logging TextClassifier related events.
- *
- * @param config logger configuration
- * @hide
- */
- @WorkerThread
- default Logger getLogger(@NonNull Logger.Config config) {
- Preconditions.checkNotNull(config);
- return Logger.DISABLED;
- }
-
- /**
* Reports a selection event.
*
* <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7e3748a..2213355 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -94,11 +94,7 @@
private final Object mLoggerLock = new Object();
@GuardedBy("mLoggerLock") // Do not access outside this lock.
- private Logger.Config mLoggerConfig;
- @GuardedBy("mLoggerLock") // Do not access outside this lock.
- private Logger mLogger;
- @GuardedBy("mLoggerLock") // Do not access outside this lock.
- private Logger mLogger2; // This is the new logger. Will replace mLogger.
+ private SelectionSessionLogger mSessionLogger;
private final TextClassificationConstants mSettings;
@@ -283,28 +279,14 @@
}
}
- /** @inheritDoc */
- @Override
- public Logger getLogger(@NonNull Logger.Config config) {
- Preconditions.checkNotNull(config);
- synchronized (mLoggerLock) {
- if (mLogger == null || !config.equals(mLoggerConfig)) {
- mLoggerConfig = config;
- mLogger = new DefaultLogger(config);
- }
- }
- return mLogger;
- }
-
@Override
public void onSelectionEvent(SelectionEvent event) {
Preconditions.checkNotNull(event);
synchronized (mLoggerLock) {
- if (mLogger2 == null) {
- mLogger2 = new DefaultLogger(
- new Logger.Config(mContext, WIDGET_TYPE_UNKNOWN, null));
+ if (mSessionLogger == null) {
+ mSessionLogger = new SelectionSessionLogger();
}
- mLogger2.writeEvent(event);
+ mSessionLogger.writeEvent(event);
}
}
@@ -331,7 +313,7 @@
private String createId(String text, int start, int end) {
synchronized (mLock) {
- return DefaultLogger.createId(text, start, end, mContext, mModel.getVersion(),
+ return SelectionSessionLogger.createId(text, start, end, mContext, mModel.getVersion(),
mModel.getSupportedLocales());
}
}
diff --git a/core/java/android/webkit/FindAddress.java b/core/java/android/webkit/FindAddress.java
index 31b2427..9183227 100644
--- a/core/java/android/webkit/FindAddress.java
+++ b/core/java/android/webkit/FindAddress.java
@@ -429,20 +429,21 @@
// At this point we've matched a state; try to match a zip code after it.
Matcher zipMatcher = sWordRe.matcher(content);
- if (zipMatcher.find(stateMatch.end())
- && isValidZipCode(zipMatcher.group(0), stateMatch)) {
- return zipMatcher.end();
+ if (zipMatcher.find(stateMatch.end())) {
+ if (isValidZipCode(zipMatcher.group(0), stateMatch)) {
+ return zipMatcher.end();
+ }
+ } else {
+ // The content ends with a state but no zip
+ // code. This is a legal match according to the
+ // documentation. N.B. This is equivalent to the
+ // original c++ implementation, which only allowed
+ // the zip code to be optional at the end of the
+ // string, which presumably is a bug. We tried
+ // relaxing this to work in other places but it
+ // caused too many false positives.
+ nonZipMatch = stateMatch.end();
}
- // The content ends with a state but no zip
- // code. This is a legal match according to the
- // documentation. N.B. This differs from the
- // original c++ implementation, which only allowed
- // the zip code to be optional at the end of the
- // string, which presumably is a bug. Now we
- // prefer to find a match with a zip code, but
- // remember non-zip matches and return them if
- // necessary.
- nonZipMatch = stateMatch.end();
}
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 9946726..6af678b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -6031,7 +6031,9 @@
mSwitchedLines = false;
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
- if (selectionStart > selectionEnd) {
+ if (selectionStart < 0 || selectionEnd < 0) {
+ Selection.removeSelection((Spannable) mTextView.getText());
+ } else if (selectionStart > selectionEnd) {
Selection.setSelection((Spannable) mTextView.getText(),
selectionEnd, selectionStart);
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index b3327a7..468abdc 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,9 +33,9 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.ActionMode;
-import android.view.textclassifier.Logger;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.SelectionEvent.InvocationMethod;
+import android.view.textclassifier.SelectionSessionLogger;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationManager;
@@ -663,7 +663,6 @@
private static final String LOG_TAG = "SelectionMetricsLogger";
private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\s+");
- private final Logger mLogger;
private final boolean mEditTextLogger;
private final BreakIterator mTokenIterator;
@@ -673,10 +672,8 @@
SelectionMetricsLogger(TextView textView) {
Preconditions.checkNotNull(textView);
- mLogger = textView.getTextClassifier().getLogger(
- new Logger.Config(textView.getContext(), getWidetType(textView), null));
mEditTextLogger = textView.isTextEditable();
- mTokenIterator = mLogger.getTokenIterator(textView.getTextLocale());
+ mTokenIterator = SelectionSessionLogger.getTokenIterator(textView.getTextLocale());
}
@TextClassifier.WidgetType
@@ -702,8 +699,6 @@
}
mTokenIterator.setText(mText);
mStartIndex = index;
- mLogger.logSelectionStartedEvent(invocationMethod, 0);
- // TODO: Remove the above legacy logging.
mClassificationSession = classificationSession;
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionStartedEvent(invocationMethod, 0));
@@ -720,27 +715,18 @@
Preconditions.checkArgumentInRange(end, start, mText.length(), "end");
int[] wordIndices = getWordDelta(start, end);
if (selection != null) {
- mLogger.logSelectionModifiedEvent(
- wordIndices[0], wordIndices[1], selection);
- // TODO: Remove the above legacy logging.
if (mClassificationSession != null) {
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionModifiedEvent(
wordIndices[0], wordIndices[1], selection));
}
} else if (classification != null) {
- mLogger.logSelectionModifiedEvent(
- wordIndices[0], wordIndices[1], classification);
- // TODO: Remove the above legacy logging.
if (mClassificationSession != null) {
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionModifiedEvent(
wordIndices[0], wordIndices[1], classification));
}
} else {
- mLogger.logSelectionModifiedEvent(
- wordIndices[0], wordIndices[1]);
- // TODO: Remove the above legacy logging.
if (mClassificationSession != null) {
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionModifiedEvent(
@@ -762,18 +748,12 @@
Preconditions.checkArgumentInRange(end, start, mText.length(), "end");
int[] wordIndices = getWordDelta(start, end);
if (classification != null) {
- mLogger.logSelectionActionEvent(
- wordIndices[0], wordIndices[1], action, classification);
- // TODO: Remove the above legacy logging.
if (mClassificationSession != null) {
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionActionEvent(
wordIndices[0], wordIndices[1], action, classification));
}
} else {
- mLogger.logSelectionActionEvent(
- wordIndices[0], wordIndices[1], action);
- // TODO: Remove the above legacy logging.
if (mClassificationSession != null) {
mClassificationSession.onSelectionEvent(
SelectionEvent.createSelectionActionEvent(
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a120e9b..dbcd2d0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9396,7 +9396,7 @@
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
- return selectionStart >= 0 && selectionStart != selectionEnd;
+ return selectionStart >= 0 && selectionEnd > 0 && selectionStart != selectionEnd;
}
String getSelectedText() {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 9a082ec..ddba477 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -129,16 +129,16 @@
}
// ----------------------------------------------------------------------
- public static boolean isSystemIme(InputMethodInfo inputMethod) {
- return (inputMethod.getServiceInfo().applicationInfo.flags
- & ApplicationInfo.FLAG_SYSTEM) != 0;
+ @Deprecated
+ public static boolean isSystemIme(@NonNull InputMethodInfo inputMethod) {
+ return inputMethod.isSystem();
}
public static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
final Context context, final boolean checkDefaultAttribute,
@Nullable final Locale requiredLocale, final boolean checkCountry,
final String requiredSubtypeMode) {
- if (!isSystemIme(imi)) {
+ if (!imi.isSystem()) {
return false;
}
if (checkDefaultAttribute && !imi.isDefault(context)) {
@@ -182,7 +182,7 @@
private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(final InputMethodInfo imi,
final Context context, final boolean checkDefaultAttribute) {
- if (!isSystemIme(imi)) {
+ if (!imi.isSystem()) {
return false;
}
if (checkDefaultAttribute && !imi.isDefault(context)) {
@@ -435,12 +435,11 @@
if (imi.isAuxiliaryIme()) {
continue;
}
- if (InputMethodUtils.isSystemIme(imi)
- && containsSubtypeOf(imi, ENGLISH_LOCALE, false /* checkCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
+ if (imi.isSystem() && containsSubtypeOf(
+ imi, ENGLISH_LOCALE, false /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
return imi;
}
- if (firstFoundSystemIme < 0 && InputMethodUtils.isSystemIme(imi)) {
+ if (firstFoundSystemIme < 0 && imi.isSystem()) {
firstFoundSystemIme = i;
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b0f68cd..3f58afa 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -327,6 +327,11 @@
transaction->setAnimationTransaction();
}
+static void nativeSetEarlyWakeup(JNIEnv* env, jclass clazz, jlong transactionObj) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ transaction->setEarlyWakeup();
+}
+
static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint zorder) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -934,6 +939,8 @@
(void*)nativeMergeTransaction },
{"nativeSetAnimationTransaction", "(J)V",
(void*)nativeSetAnimationTransaction },
+ {"nativeSetEarlyWakeup", "(J)V",
+ (void*)nativeSetEarlyWakeup },
{"nativeSetLayer", "(JJI)V",
(void*)nativeSetLayer },
{"nativeSetRelativeLayer", "(JJLandroid/os/IBinder;I)V",
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 2a7c256..ab15d4f 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -118,17 +118,17 @@
// Stack dumps
optional android.os.BackTraceProto native_traces = 1200 [
- (section).type = SECTION_NONE,
+ (section).type = SECTION_TOMBSTONE,
(section).args = "native"
];
optional android.os.BackTraceProto hal_traces = 1201 [
- (section).type = SECTION_NONE,
+ (section).type = SECTION_TOMBSTONE,
(section).args = "hal"
];
optional android.os.BackTraceProto java_traces = 1202 [
- (section).type = SECTION_NONE,
+ (section).type = SECTION_TOMBSTONE,
(section).args = "java"
];
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3de8c39..237efd8 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -213,6 +213,13 @@
optional SettingProto keyguard_slice_uri = 29;
optional SettingProto last_setup_shown = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ message Launcher {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto swipe_up_to_switch_apps_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Launcher launcher = 70;
+
message Location {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -479,5 +486,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 70;
+ // Next tag = 71;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8443a67..4ce89c9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -974,6 +974,9 @@
-->
<integer name="config_longPressOnBackBehavior">0</integer>
+ <!-- Allows activities to be launched on a long press on power during device setup. -->
+ <bool name="config_allowStartActivityForLongPressOnPowerInSetup">false</bool>
+
<!-- Control the behavior when the user short presses the power button.
0 - Nothing
1 - Go to sleep (doze)
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 1a51c1d..d722961 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -128,6 +128,9 @@
<style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Material.TextSelectHandle"/>
<style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Material.TextView.ListSeparator"/>
<style name="Widget.DeviceDefault.TimePicker" parent="Widget.Material.TimePicker"/>
+ <style name="Widget.DeviceDefault.Toolbar" parent="Widget.Material.Toolbar">
+ <item name="titleTextAppearance">@style/TextAppearance.DeviceDefault.Widget.Toolbar.Title</item>
+ </style>
<style name="Widget.DeviceDefault.Light" parent="Widget.Material.Light"/>
<style name="Widget.DeviceDefault.Light.Button" parent="Widget.Material.Light.Button"/>
@@ -186,7 +189,9 @@
<style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Material.Light.ActionBar.TabView"/>
<style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Material.Light.ActionBar.TabText"/>
<style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Material.Light.ActionBar.TabBar"/>
- <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Material.Light.ActionBar.Solid"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Material.Light.ActionBar.Solid">
+ <item name="titleTextStyle">@style/TextAppearance.DeviceDefault.Widget.ActionBar.Title</item>
+ </style>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" parent="Widget.Holo.Light.ActionBar.Solid.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
@@ -242,12 +247,18 @@
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Material.Widget.PopupMenu"/>
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Material.Widget.PopupMenu.Large"/>
<style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Material.Widget.PopupMenu.Small"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Material.Widget.ActionBar.Title"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Material.Widget.ActionBar.Title">
+ <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
+ </style>
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Widget.ActionBar.Subtitle"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Material.Widget.ActionMode.Title"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Material.Widget.ActionMode.Subtitle"/>
- <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Material.WindowTitle"/>
- <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Material.DialogWindowTitle"/>
+ <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Material.WindowTitle">
+ <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Material.DialogWindowTitle">
+ <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
+ </style>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Material.Widget.ActionBar.Title.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
@@ -257,6 +268,7 @@
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Material.Widget.ActionBar.Menu"/>
+ <style name="TextAppearance.DeviceDefault.Widget.Toolbar.Title" parent="TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
<!-- Preference Styles -->
<style name="Preference.DeviceDefault" parent="Preference.Material"/>
@@ -280,11 +292,15 @@
<style name="Animation.DeviceDefault.Dialog" parent="Animation.Material.Dialog"/>
<!-- DialogWindowTitle Styles -->
- <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Material"/>
- <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Material.Light"/>
+ <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Material">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.DialogWindowTitle</item>
+ </style>
+ <style name="DialogWindowTitle.DeviceDefault.Light"/>
<!-- WindowTitle Styles -->
- <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Material"/>
+ <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Material">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.WindowTitle</item>
+ </style>
<style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Material"/>
<!-- Other Styles -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5856648..ce7f1ff 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -434,6 +434,7 @@
<java-symbol type="integer" name="config_veryLongPressOnPowerBehavior" />
<java-symbol type="integer" name="config_veryLongPressTimeout" />
<java-symbol type="integer" name="config_longPressOnBackBehavior" />
+ <java-symbol type="bool" name="config_allowStartActivityForLongPressOnPowerInSetup" />
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
<java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
<java-symbol type="integer" name="config_max_pan_devices" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 2327b33..fd6cc95 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -181,6 +181,9 @@
<item name="actionBarStyle">@style/Widget.DeviceDefault.ActionBar.Solid</item>
<item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
+
<item name="buttonBarStyle">@style/DeviceDefault.ButtonBar</item>
<item name="segmentedButtonStyle">@style/DeviceDefault.SegmentedButton</item>
@@ -233,6 +236,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -257,6 +263,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -283,6 +292,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -308,6 +320,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -341,6 +356,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -365,6 +383,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -388,6 +409,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -412,6 +436,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -452,6 +479,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -477,6 +507,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -500,6 +533,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -525,6 +561,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -549,6 +588,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -573,6 +615,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -597,6 +642,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -621,6 +669,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -645,6 +696,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
@@ -667,6 +721,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -689,6 +746,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -822,6 +882,9 @@
<item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
<item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
+
<item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar</item>
<item name="segmentedButtonStyle">@style/DeviceDefault.Light.SegmentedButton</item>
@@ -869,6 +932,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -892,6 +958,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -916,6 +985,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -942,6 +1014,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -967,6 +1042,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -998,11 +1076,17 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
regular dialog. -->
<style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1022,10 +1106,16 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
<style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1045,11 +1135,17 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
width for a regular dialog. -->
<style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1069,6 +1165,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -1100,6 +1199,9 @@
<!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
<style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1119,12 +1221,18 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
xlarge). -->
<style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1144,10 +1252,16 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
<style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -1167,6 +1281,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -1192,6 +1309,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -1216,6 +1336,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -1238,6 +1361,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -1260,11 +1386,15 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
<style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
<!-- action bar -->
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
<item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar.Accent</item>
<item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
@@ -1295,6 +1425,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -1319,6 +1452,9 @@
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
+
<!-- volume background -->
<item name="panelColorBackground">@color/primary_material_light</item>
</style>
@@ -1334,6 +1470,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -1358,9 +1497,15 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_settings</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
@@ -1381,9 +1526,15 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_settings</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
@@ -1404,9 +1555,15 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_settings</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
@@ -1427,6 +1584,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -1461,6 +1621,9 @@
<!-- Progress bar attributes -->
<item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
+ <!-- Toolbar attributes -->
+ <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
<!-- DeviceDefault theme for the default system theme. -->
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7c6d7b1..613ab6d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -303,6 +303,12 @@
Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
+ Settings.Global.NETPOLICY_QUOTA_ENABLED,
+ Settings.Global.NETPOLICY_QUOTA_UNLIMITED,
+ Settings.Global.NETPOLICY_QUOTA_LIMITED,
+ Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS,
+ Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH,
+ Settings.Global.NETPOLICY_OVERRIDE_ENABLED,
Settings.Global.NETWORK_AVOID_BAD_WIFI,
Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
@@ -413,6 +419,7 @@
Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
+ Settings.Global.UNGAZE_SLEEP_ENABLED,
Settings.Global.UNLOCK_SOUND,
Settings.Global.USE_GOOGLE_MAIL,
Settings.Global.VT_IMS_ENABLED,
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index 307ac62..f368428 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -16,6 +16,8 @@
package android.text;
+import static org.junit.Assert.assertEquals;
+
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -24,6 +26,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -53,4 +57,34 @@
spans = spannable.getSpans(2, 2, Object.class);
MoreAsserts.assertEquals(new Object[]{unemptySpan}, spans);
}
+
+ @Test
+ public void testRemoveSpanWithIntermediateFlag() {
+ Spannable spannable = newSpannableWithText("abcdef");
+ Object emptySpan = new Object();
+ spannable.setSpan(emptySpan, 1, 1, 0);
+ Object unemptySpan = new Object();
+ spannable.setSpan(unemptySpan, 1, 2, 0);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ SpanWatcher watcher = new SpanWatcher() {
+ @Override
+ public void onSpanAdded(Spannable text, Object what, int start, int end) {}
+
+ @Override
+ public void onSpanRemoved(Spannable text, Object what, int start, int end) {
+ latch.countDown();
+ }
+
+ @Override
+ public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart,
+ int nend) {}
+ };
+ spannable.setSpan(watcher, 0, 2, 0);
+
+ spannable.removeSpan(emptySpan, Spanned.SPAN_INTERMEDIATE);
+ assertEquals(1, latch.getCount());
+ spannable.removeSpan(unemptySpan);
+ assertEquals(0, latch.getCount());
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
index 861a43a..a3c6179 100644
--- a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -31,20 +30,34 @@
public class SelectionEventTest {
@Test
+ public void testCreateSelectionActionEvent_valid() {
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_OVERTYPE);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_COPY);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_PASTE);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_CUT);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_SHARE);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_SMART_SHARE);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_DRAG);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_ABANDON);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_OTHER);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_SELECT_ALL);
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.ACTION_RESET);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateSelectionActionEvent_badRange() {
+ SelectionEvent.createSelectionActionEvent(0, -1, SelectionEvent.ACTION_OVERTYPE);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateSelectionActionEvent_badAction() {
+ SelectionEvent.createSelectionActionEvent(0, 1, SelectionEvent.EVENT_SELECTION_STARTED);
+ }
+
+ @Test
public void testParcel() {
- final SelectionEvent[] captured = new SelectionEvent[1];
- final Logger logger = new Logger(
- new Logger.Config(
- InstrumentationRegistry.getTargetContext(),
- TextClassifier.WIDGET_TYPE_TEXTVIEW,
- null)) {
- @Override
- public void writeEvent(SelectionEvent event) {
- captured[0] = event;
- }
- };
- logger.logSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, 0);
- final SelectionEvent event = captured[0];
+ final SelectionEvent event = SelectionEvent.createSelectionStartedEvent(
+ SelectionEvent.INVOCATION_MANUAL, 0);
final Parcel parcel = Parcel.obtain();
event.writeToParcel(parcel, event.describeContents());
parcel.setDataPosition(0);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 20c22b7..18dd97f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -738,6 +738,23 @@
/**
* Creates a typeface object that best matches the specified existing typeface and the specified
* weight and italic style
+ * <p>Below are numerical values and corresponding common weight names.</p>
+ * <table>
+ * <thead>
+ * <tr><th>Value</th><th>Common weight name</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><td>100</td><td>Thin</td></tr>
+ * <tr><td>200</td><td>Extra Light</td></tr>
+ * <tr><td>300</td><td>Light</td></tr>
+ * <tr><td>400</td><td>Normal</td></tr>
+ * <tr><td>500</td><td>Medium</td></tr>
+ * <tr><td>600</td><td>Semi Bold</td></tr>
+ * <tr><td>700</td><td>Bold</td></tr>
+ * <tr><td>800</td><td>Extra Bold</td></tr>
+ * <tr><td>900</td><td>Black</td></tr>
+ * </tbody>
+ * </table>
*
* <p>
* This method is thread safe.
@@ -749,6 +766,9 @@
* @param italic {@code true} if italic style is desired to be drawn. Otherwise, {@code false}
* @return A {@link Typeface} object for drawing specified weight and italic style. Never
* returns {@code null}
+ *
+ * @see #getWeight()
+ * @see #isItalic()
*/
public static @NonNull Typeface create(@Nullable Typeface family,
@IntRange(from = 1, to = 1000) int weight, boolean italic) {
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index f9cf549..1696661 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -104,7 +104,8 @@
dprintf(fd, "\nStats since: %" PRIu64 "ns", mStatStartTime);
dprintf(fd, "\nTotal frames rendered: %u", mTotalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", mJankFrameCount,
- (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f);
+ mTotalFrameCount == 0 ? 0.0f :
+ (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f);
dprintf(fd, "\n50th percentile: %ums", findPercentile(50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(95));
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 38286a3..6eb3d8d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -29,6 +29,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -392,6 +393,18 @@
}
/**
+ * @hide
+ */
+ @TestApi
+ public String[] getBackgroundThrottlingWhitelist() {
+ try {
+ return mService.getBackgroundThrottlingWhitelist();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide - hide this constructor because it has a parameter
* of type ILocationManager, which is a system private class. The
* right way to create an instance of this class is using the
diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java
index 7104dad..fe89b89 100644
--- a/media/java/android/media/AudioFocusRequest.java
+++ b/media/java/android/media/AudioFocusRequest.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.os.Bundle;
import android.os.Handler;
@@ -262,6 +263,7 @@
* Returns the focus change listener set for this {@code AudioFocusRequest}.
* @return null if no {@link AudioManager.OnAudioFocusChangeListener} was set.
*/
+ @TestApi
public @Nullable OnAudioFocusChangeListener getOnAudioFocusChangeListener() {
return mFocusListener;
}
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index e39cb7d..ce71436 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -18,8 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
+import android.annotation.TestApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -94,7 +93,7 @@
/**
* @hide
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ @TestApi
public AudioPresentation(int presentationId,
int programId,
@NonNull Map<String, String> labels,
@@ -119,7 +118,7 @@
* decoder. Presentation id is typically sequential, but does not have to be.
* @hide
*/
- @VisibleForTesting
+ @TestApi
public int getPresentationId() {
return mPresentationId;
}
@@ -129,7 +128,7 @@
* Program id can be used to further uniquely identify the presentation to a decoder.
* @hide
*/
- @VisibleForTesting
+ @TestApi
public int getProgramId() {
return mProgramId;
}
diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java
index 938a953..b85e4d0 100644
--- a/media/java/android/media/PlaybackParams.java
+++ b/media/java/android/media/PlaybackParams.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -151,6 +152,7 @@
* @param audioStretchMode
* @return this <code>PlaybackParams</code> instance.
*/
+ @TestApi
public PlaybackParams setAudioStretchMode(@AudioStretchMode int audioStretchMode) {
mAudioStretchMode = audioStretchMode;
mSet |= SET_AUDIO_STRETCH_MODE;
@@ -163,6 +165,7 @@
* @return audio stretch mode
* @throws IllegalStateException if the audio stretch mode is not set.
*/
+ @TestApi
public @AudioStretchMode int getAudioStretchMode() {
if ((mSet & SET_AUDIO_STRETCH_MODE) == 0) {
throw new IllegalStateException("audio stretch mode not set");
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 48ddf9a..51b080a3 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -110,16 +110,16 @@
effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
JNIEnv *env = AndroidRuntime::getJNIEnv();
- ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
- callbackInfo,
- callbackInfo->audioEffect_ref,
- callbackInfo->audioEffect_class);
-
if (!user || !env) {
ALOGW("effectCallback error user %p, env %p", user, env);
return;
}
+ ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
+ callbackInfo,
+ callbackInfo->audioEffect_ref,
+ callbackInfo->audioEffect_class);
+
switch (event) {
case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
if (info == 0) {
diff --git a/packages/SettingsLib/res/layout/preference_category_material_settings.xml b/packages/SettingsLib/res/layout/preference_category_material_settings.xml
index 245e3b7..1086106 100644
--- a/packages/SettingsLib/res/layout/preference_category_material_settings.xml
+++ b/packages/SettingsLib/res/layout/preference_category_material_settings.xml
@@ -50,6 +50,7 @@
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textAppearance="@android:style/TextAppearance.Material.Body2"
android:textAlignment="viewStart"
android:textColor="?android:attr/colorAccent"
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 7b09ef7..cf4261c 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -33,6 +33,8 @@
<dimen name="user_spinner_item_height">56dp</dimen>
<dimen name="two_target_pref_small_icon_size">24dp</dimen>
+ <dimen name="two_target_pref_medium_icon_size">32dp</dimen>
+
<!-- Lock icon for preferences locked by admin -->
<dimen name="restricted_icon_size">16dp</dimen>
<dimen name="restricted_icon_padding">4dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java b/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java
index 8b39f60..02b68d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java
@@ -16,6 +16,7 @@
package com.android.settingslib;
+import android.annotation.IntDef;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
@@ -24,10 +25,24 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class TwoTargetPreference extends Preference {
- private boolean mUseSmallIcon;
+ @IntDef({ICON_SIZE_DEFAULT, ICON_SIZE_MEDIUM, ICON_SIZE_SMALL})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IconSize {
+ }
+
+ public static final int ICON_SIZE_DEFAULT = 0;
+ public static final int ICON_SIZE_MEDIUM = 1;
+ public static final int ICON_SIZE_SMALL = 2;
+
+ @IconSize
+ private int mIconSize;
private int mSmallIconSize;
+ private int mMediumIconSize;
public TwoTargetPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
@@ -54,22 +69,30 @@
setLayoutResource(R.layout.preference_two_target);
mSmallIconSize = context.getResources().getDimensionPixelSize(
R.dimen.two_target_pref_small_icon_size);
+ mMediumIconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.two_target_pref_medium_icon_size);
final int secondTargetResId = getSecondTargetResId();
if (secondTargetResId != 0) {
setWidgetLayoutResource(secondTargetResId);
}
}
- public void setUseSmallIcon(boolean useSmallIcon) {
- mUseSmallIcon = useSmallIcon;
+ public void setIconSize(@IconSize int iconSize) {
+ mIconSize = iconSize;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- if (mUseSmallIcon) {
- ImageView icon = holder.itemView.findViewById(android.R.id.icon);
- icon.setLayoutParams(new LinearLayout.LayoutParams(mSmallIconSize, mSmallIconSize));
+ final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
+ switch (mIconSize) {
+ case ICON_SIZE_SMALL:
+ icon.setLayoutParams(new LinearLayout.LayoutParams(mSmallIconSize, mSmallIconSize));
+ break;
+ case ICON_SIZE_MEDIUM:
+ icon.setLayoutParams(
+ new LinearLayout.LayoutParams(mMediumIconSize, mMediumIconSize));
+ break;
}
final View divider = holder.findViewById(R.id.two_target_divider);
final View widgetFrame = holder.findViewById(android.R.id.widget_frame);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
new file mode 100644
index 0000000..941964a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -0,0 +1,200 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * HidProfile handles Bluetooth HID profile.
+ */
+public class HidDeviceProfile implements LocalBluetoothProfile {
+ private static final String TAG = "HidDeviceProfile";
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 18;
+ // HID Device Profile is always preferred.
+ private static final int PREFERRED_VALUE = -1;
+ private static final boolean DEBUG = true;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+ private final LocalBluetoothProfileManager mProfileManager;
+ static final String NAME = "HID DEVICE";
+
+ private BluetoothHidDevice mService;
+ private boolean mIsProfileReady;
+
+ HidDeviceProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ adapter.getProfileProxy(context, new HidDeviceServiceListener(),
+ BluetoothProfile.HID_DEVICE);
+ }
+
+ // These callbacks run on the main thread.
+ private final class HidDeviceServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG,"Bluetooth service connected :-)");
+ }
+ mService = (BluetoothHidDevice) proxy;
+ // We just bound to the service, so refresh the UI for any connected HID devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ for (BluetoothDevice nextDevice : deviceList) {
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "HidProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ Log.d(TAG, "Connection status changed: " + device);
+ device.onProfileStateChanged(HidDeviceProfile.this,
+ BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (DEBUG) {
+ Log.d(TAG, "Bluetooth service disconnected");
+ }
+ mIsProfileReady = false;
+ }
+ }
+
+ @Override
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ @Override
+ public boolean isConnectable() {
+ return true;
+ }
+
+ @Override
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ @Override
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ @Override
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) {
+ return false;
+ }
+ return mService.disconnect(device);
+ }
+
+ @Override
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+
+ return !deviceList.isEmpty() && deviceList.contains(device)
+ ? mService.getConnectionState(device)
+ : BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ @Override
+ public boolean isPreferred(BluetoothDevice device) {
+ return getConnectionStatus(device) != BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ @Override
+ public int getPreferred(BluetoothDevice device) {
+ return PREFERRED_VALUE;
+ }
+
+ @Override
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // if set preferred to false, then disconnect to the current device
+ if (!preferred) {
+ mService.disconnect(device);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return NAME;
+ }
+
+ @Override
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ @Override
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_hid;
+ }
+
+ @Override
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ final int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_hid_profile_summary_use_for;
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_hid_profile_summary_connected;
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ @Override
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_misc_hid;
+ }
+
+ protected void finalize() {
+ if (DEBUG) {
+ Log.d(TAG, "finalize()");
+ }
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_DEVICE,
+ mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up HID proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 213002f..93c4017 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -48,7 +48,7 @@
private static final int ORDINAL = 3;
// These callbacks run on the main thread.
- private final class InputDeviceServiceListener
+ private final class HidHostServiceListener
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -86,7 +86,7 @@
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- adapter.getProfileProxy(context, new InputDeviceServiceListener(),
+ adapter.getProfileProxy(context, new HidHostServiceListener(),
BluetoothProfile.HID_HOST);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 00ee575..6413aab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothHidDevice;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
@@ -86,6 +87,7 @@
private MapProfile mMapProfile;
private MapClientProfile mMapClientProfile;
private final HidProfile mHidProfile;
+ private HidDeviceProfile mHidDeviceProfile;
private OppProfile mOppProfile;
private final PanProfile mPanProfile;
private PbapClientProfile mPbapClientProfile;
@@ -123,7 +125,7 @@
updateLocalProfiles(uuids);
}
- // Always add HID and PAN profiles
+ // Always add HID host, HID device, and PAN profiles
mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
addProfile(mHidProfile, HidProfile.NAME,
BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
@@ -132,6 +134,10 @@
addPanProfile(mPanProfile, PanProfile.NAME,
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+ mHidDeviceProfile = new HidDeviceProfile(context, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
+ BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
+
if(DEBUG) Log.d(TAG, "Adding local MAP profile");
if (mUseMapClient) {
mMapClientProfile = new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
@@ -547,6 +553,12 @@
removedProfiles.remove(mHidProfile);
}
+ if (mHidProfile != null && mHidDeviceProfile.getConnectionStatus(device)
+ != BluetoothProfile.STATE_DISCONNECTED) {
+ profiles.add(mHidDeviceProfile);
+ removedProfiles.remove(mHidDeviceProfile);
+ }
+
if(isPanNapConnected)
if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 835ff07..f7b16f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -148,15 +148,32 @@
Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
}
+ /**
+ * Don't show the automatic battery suggestion notification in the future.
+ */
public static void suppressAutoBatterySaver(Context context) {
Secure.putInt(context.getContentResolver(),
Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 1);
}
- public static void scheduleAutoBatterySaver(Context context, int level) {
+ /**
+ * Set the automatic battery saver trigger level to {@code level}.
+ */
+ public static void setAutoBatterySaverTriggerLevel(Context context, int level) {
+ if (level > 0) {
+ suppressAutoBatterySaver(context);
+ }
+ Global.putInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, level);
+ }
+
+ /**
+ * Set the automatic battery saver trigger level to {@code level}, but only when
+ * automatic battery saver isn't enabled yet.
+ */
+ public static void ensureAutoBatterySaver(Context context, int level) {
if (Global.getInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)
== 0) {
- Global.putInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, level);
+ setAutoBatterySaverTriggerLevel(context, level);
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
index 55be137..e63bdd6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java
@@ -35,7 +35,6 @@
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.app.LocaleHelper;
-import com.android.internal.inputmethod.InputMethodUtils;
import java.util.HashMap;
import java.util.HashSet;
@@ -176,7 +175,7 @@
((TwoStatePreference) pref).isChecked()
: enabledIMEsAndSubtypesMap.containsKey(imiId);
final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId);
- final boolean systemIme = InputMethodUtils.isSystemIme(imi);
+ final boolean systemIme = imi.isSystem();
if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance(
context.getActivity()).isAlwaysCheckedIme(imi, context.getActivity()))
|| isImeChecked) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
index 5e25f51..649a864 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
@@ -35,7 +35,6 @@
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.inputmethod.InputMethodUtils;
import com.android.settingslib.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -124,7 +123,7 @@
setIntent(intent);
}
mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(context);
- mHasPriorityInSorting = InputMethodUtils.isSystemIme(imi)
+ mHasPriorityInSorting = imi.isSystem()
&& mInputMethodSettingValues.isValidSystemNonAuxAsciiCapableIme(imi, context);
setOnPreferenceClickListener(this);
setOnPreferenceChangeListener(this);
@@ -153,7 +152,7 @@
setCheckedInternal(false);
return false;
}
- if (InputMethodUtils.isSystemIme(mImi)) {
+ if (mImi.isSystem()) {
// Enable a system IME. No need to show a security warning dialog,
// but we might need to prompt if it's not Direct Boot aware.
// TV doesn't doesn't need to worry about this, but other platforms should show
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
index fac50bd..554fb35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
@@ -129,7 +129,7 @@
return enabledValidSystemNonAuxAsciiCapableImeCount <= 1
&& !(enabledValidSystemNonAuxAsciiCapableImeCount == 1 && !isEnabled)
- && InputMethodUtils.isSystemIme(imi)
+ && imi.isSystem()
&& isValidSystemNonAuxAsciiCapableIme(imi, context);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 9347674..547cd9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -41,8 +41,9 @@
private final WifiManager mWifiManager;
private final NetworkScoreManager mNetworkScoreManager;
private final ConnectivityManager mConnectivityManager;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
private final WifiNetworkScoreCache.CacheListener mCacheListener =
- new WifiNetworkScoreCache.CacheListener(new Handler(Looper.getMainLooper())) {
+ new WifiNetworkScoreCache.CacheListener(mHandler) {
@Override
public void networkCacheUpdated(List<ScoredNetwork> updatedNetworks) {
updateStatusLabel();
@@ -89,7 +90,8 @@
mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
mWifiNetworkScoreCache.registerListener(mCacheListener);
- mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ mConnectivityManager.registerNetworkCallback(
+ mNetworkRequest, mNetworkCallback, mHandler);
} else {
mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI,
mWifiNetworkScoreCache);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index a128b54..d8f0886 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -313,7 +313,8 @@
mContext.registerReceiver(mReceiver, mFilter, null /* permission */, mWorkHandler);
// NetworkCallback objects cannot be reused. http://b/20701525 .
mNetworkCallback = new WifiTrackerNetworkCallback();
- mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ mConnectivityManager.registerNetworkCallback(
+ mNetworkRequest, mNetworkCallback, mWorkHandler);
mRegistered = true;
}
}
@@ -788,7 +789,7 @@
// We don't send a NetworkInfo object along with this message, because even if we
// fetch one from ConnectivityManager, it might be older than the most recent
// NetworkInfo message we got via a WIFI_STATE_CHANGED broadcast.
- mWorkHandler.post(() -> updateNetworkInfo(null));
+ updateNetworkInfo(null);
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
index c5e93f0..480143a7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib;
+import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_DEFAULT;
+import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM;
+import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_SMALL;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -75,8 +78,8 @@
}
@Test
- public void bind_smallIcon_shouldUseSmallIcon() {
- mPreference.setUseSmallIcon(true);
+ public void bind_smallIcon_shouldUseSmallIconSize() {
+ mPreference.setIconSize(ICON_SIZE_SMALL);
mPreference.onBindViewHolder(mViewHolder);
@@ -91,8 +94,24 @@
}
@Test
- public void bind_normalIcon_shouldUseNormalIcon() {
- mPreference.setUseSmallIcon(false);
+ public void bind_mediumIcon_shouldUseMediumIconSize() {
+ mPreference.setIconSize(ICON_SIZE_MEDIUM);
+
+ mPreference.onBindViewHolder(mViewHolder);
+
+ final int size = mContext.getResources().getDimensionPixelSize(
+ R.dimen.two_target_pref_medium_icon_size);
+ final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mViewHolder
+ .findViewById(android.R.id.icon)
+ .getLayoutParams();
+
+ assertThat(layoutParams.width).isEqualTo(size);
+ assertThat(layoutParams.height).isEqualTo(size);
+ }
+
+ @Test
+ public void bind_defaultIcon_shouldUseDefaultIconSize() {
+ mPreference.setIconSize(ICON_SIZE_DEFAULT);
mPreference.onBindViewHolder(mViewHolder);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
index b33df30..ba5a2c5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
@@ -16,7 +16,9 @@
package com.android.settingslib.fuelgauge;
+import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -28,6 +30,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
+import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
@@ -41,6 +44,9 @@
@RunWith(SettingsLibRobolectricTestRunner.class)
public class BatterySaverUtilsTest {
+ final int BATTERY_SAVER_THRESHOLD_1 = 15;
+ final int BATTERY_SAVER_THRESHOLD_2 = 20;
+
@Mock
Context mMockContext;
@@ -149,4 +155,37 @@
assertEquals(-2,
Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
}
+
+ @Test
+ public void testEnsureAutoBatterysaver_setNewPositiveValue_doNotOverwrite() throws Exception {
+ Global.putString(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, "null");
+
+ BatterySaverUtils.ensureAutoBatterySaver(mMockContext, BATTERY_SAVER_THRESHOLD_1);
+
+ assertThat(Secure.getInt(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
+ .isEqualTo(BATTERY_SAVER_THRESHOLD_1);
+
+ // Once a positive number is set, ensureAutoBatterySaver() won't overwrite it.
+ BatterySaverUtils.ensureAutoBatterySaver(mMockContext, BATTERY_SAVER_THRESHOLD_2);
+ assertThat(Secure.getInt(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
+ .isEqualTo(BATTERY_SAVER_THRESHOLD_1);
+ }
+
+ @Test
+ public void testSetAutoBatterySaverTriggerLevel_setSuppressSuggestion() throws Exception {
+ Global.putString(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, "null");
+ Secure.putString(mMockResolver, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, "null");
+
+ BatterySaverUtils.setAutoBatterySaverTriggerLevel(mMockContext, 0);
+ assertThat(Global.getInt(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
+ .isEqualTo(0);
+ assertThat(Secure.getInt(mMockResolver, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, -1))
+ .isEqualTo(-1); // not set.
+
+ BatterySaverUtils.setAutoBatterySaverTriggerLevel(mMockContext, BATTERY_SAVER_THRESHOLD_1 );
+ assertThat( Global.getInt(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
+ .isEqualTo(BATTERY_SAVER_THRESHOLD_1);
+ assertThat(Secure.getInt(mMockResolver, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, -1))
+ .isEqualTo(1);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 67053d8..a2263b4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2231,6 +2231,12 @@
Settings.Secure.WAKE_GESTURE_ENABLED,
SecureSettingsProto.WAKE_GESTURE_ENABLED);
+ final long launcherToken = p.start(SecureSettingsProto.LAUNCHER);
+ dumpSetting(s, p,
+ Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED,
+ SecureSettingsProto.Launcher.SWIPE_UP_TO_SWITCH_APPS_ENABLED);
+ p.end(launcherToken);
+
// Please insert new settings using the same order as in SecureSettingsProto.
p.end(token);
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index 0ee40d7..67f68d3 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -15,40 +15,32 @@
limitations under the License.
-->
+
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:clipChildren="false"
android:alpha="0"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/car_fullscreen_user_pod_height"
- android:layout_gravity="center_horizontal|bottom" >
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:gravity="fill_horizontal"
+ android:layout_marginTop="@dimen/car_padding_5"
+ android:layout_marginStart="@dimen/car_padding_4">
<ImageView android:id="@+id/user_avatar"
android:layout_centerHorizontal="true"
- android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_image_top"
android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"
- android:layout_above="@id/user_name" />
+ />
<TextView android:id="@+id/user_name"
- android:layout_width="@dimen/car_fullscreen_user_pod_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_name_top"
- android:layout_marginBottom="@dimen/car_fullscreen_user_pod_margin_name_bottom"
- android:textSize="@dimen/car_fullscreen_user_pod_name_text_size"
+ android:layout_marginTop="@dimen/car_padding_4"
+ android:textSize="@dimen/car_body1_size"
android:textColor="@color/qs_user_detail_name"
android:ellipsize="end"
android:singleLine="true"
- android:gravity="center_horizontal"
- android:layout_above="@id/device_name" />
+ android:gravity="center"
+ android:layout_below="@id/user_avatar"/>
- <TextView android:id="@+id/device_name"
- android:layout_width="@dimen/car_fullscreen_user_pod_width"
- android:layout_height="wrap_content"
- android:textSize="@dimen/car_fullscreen_user_pod_device_text_size"
- android:textColor="@color/qs_user_detail_name"
- android:ellipsize="end"
- android:singleLine="true"
- android:gravity="center_horizontal"
- android:layout_alignParentBottom="true" />
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
deleted file mode 100644
index d666a20..0000000
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:clipChildren="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center" >
-
- <!-- car_fullscreen_user_pods will be dynamically added here. -->
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index bfabe52..22452b7 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -39,27 +39,34 @@
android:theme="@android:style/Theme"
android:layout_alignParentTop="true"/>
- <com.android.systemui.statusbar.car.UserGridView
- android:id="@+id/user_grid"
+ <RelativeLayout
+ android:id="@+id/fullscreen_user_switcher_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/car_margin"
- android:layout_marginRight="@dimen/car_margin"
- android:layout_centerInParent="true"/>
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/car_margin"
+ android:layout_marginEnd="@dimen/car_margin">
- <com.android.systemui.statusbar.car.PageIndicator
- android:id="@+id/user_switcher_page_indicator"
- android:layout_width="match_parent"
- android:layout_height="@dimen/car_page_indicator_dot_diameter"
- android:layout_below="@+id/user_grid" />
+ <RelativeLayout
+ android:id="@+id/fullscreen_user_switcher_container_inner"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/car_padding_4">
- <Button
- android:id="@+id/start_driving"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/car_start_driving_height"
- android:text="@string/start_driving"
- style="@style/CarUserSwitcher.StartDrivingButton"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true" />
+ <com.android.systemui.statusbar.car.UserGridRecyclerView
+ android:id="@+id/user_grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/header"
+ android:scrollbars="vertical"
+ android:scrollbarFadeDuration="0"
+ android:verticalScrollbarPosition="left"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"/>
+
+ </RelativeLayout>
+
+ </RelativeLayout>
+
</RelativeLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/car_left_navigation_bar.xml b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
index 18301a8..02be457 100644
--- a/packages/SystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
@@ -40,7 +40,7 @@
android:id="@+id/home"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingTop="30dp"
diff --git a/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
index a65ff16..708f595 100644
--- a/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
+++ b/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
@@ -40,7 +40,7 @@
android:id="@+id/home"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingTop="30dp"
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
index 9ff16a2..d568d0d 100644
--- a/packages/SystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/SystemUI/res/layout/car_navigation_bar.xml
@@ -38,7 +38,7 @@
android:id="@+id/home"
android:layout_height="match_parent"
android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingLeft="30dp"
diff --git a/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
index b0488ae..4ba6c06 100644
--- a/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
+++ b/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
@@ -38,7 +38,7 @@
android:id="@+id/home"
android:layout_height="match_parent"
android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingLeft="30dp"
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index 447970c..c01bbce 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -30,27 +30,29 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/user_switcher_container"
+ android:layout_marginStart="@dimen/car_margin"
+ android:layout_marginEnd="@dimen/car_margin"
android:clipChildren="false"
android:layout_width="match_parent"
- android:layout_height="@dimen/car_user_switcher_container_height"
- android:layout_gravity="center_horizontal" >
+ android:layout_height="@dimen/car_user_switcher_container_height">
- <com.android.systemui.statusbar.car.UserGridView
- android:id="@+id/user_grid"
- android:clipChildren="false"
+ <RelativeLayout
+ android:id="@+id/fullscreen_user_switcher_container_inner"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/car_margin"
- android:layout_marginRight="@dimen/car_margin"
- android:layout_above="@id/user_switcher_page_indicator" />
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/car_padding_4">
- <com.android.systemui.statusbar.car.PageIndicator
- android:id="@+id/user_switcher_page_indicator"
- android:layout_width="match_parent"
- android:layout_height="@dimen/car_page_indicator_dot_diameter"
- android:layout_marginBottom="@dimen/car_page_indicator_margin_bottom"
- android:alpha="0"
- android:layout_alignParentBottom="true" />
+ <com.android.systemui.statusbar.car.UserGridRecyclerView
+ android:id="@+id/user_grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:verticalScrollbarPosition="left"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:scrollbarFadeDuration="0"/>
+ </RelativeLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar.xml b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
index 99bd23c..91ba026 100644
--- a/packages/SystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
@@ -40,7 +40,7 @@
android:id="@+id/home"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingTop="30dp"
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
index a65ff16..708f595 100644
--- a/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
+++ b/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
@@ -40,7 +40,7 @@
android:id="@+id/home"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
android:src="@drawable/car_ic_overview"
android:background="?android:attr/selectableItemBackground"
android:paddingTop="30dp"
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 79e54aa..d72021e 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -27,13 +27,16 @@
<com.android.systemui.statusbar.phone.NearestTouchFrame
android:id="@+id/nav_buttons"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<LinearLayout
android:id="@+id/ends_group"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
+ android:clipToPadding="false"
android:clipChildren="false" />
<LinearLayout
@@ -43,6 +46,7 @@
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal"
+ android:clipToPadding="false"
android:clipChildren="false" />
</com.android.systemui.statusbar.phone.NearestTouchFrame>
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index e4ea08e..b5d48b4 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -51,12 +51,10 @@
<ImageButton
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center"
android:paddingStart="12dp"
android:paddingEnd="24dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
android:id="@+id/remote_input_send"
android:src="@drawable/ic_send"
android:contentDescription="@*android:string/ime_action_send"
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 6caed61..2b91891 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -17,18 +17,14 @@
-->
<resources>
<dimen name="car_margin">148dp</dimen>
+ <dimen name="car_margin_standard">112dp</dimen>
- <dimen name="car_fullscreen_user_pod_margin_image_top">24dp</dimen>
- <dimen name="car_fullscreen_user_pod_margin_name_top">24dp</dimen>
- <dimen name="car_fullscreen_user_pod_margin_name_bottom">20dp</dimen>
- <dimen name="car_fullscreen_user_pod_margin_between">24dp</dimen>
- <dimen name="car_fullscreen_user_pod_icon_text_size">96dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_width">192dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_height">192dp</dimen>
- <dimen name="car_fullscreen_user_pod_width">264dp</dimen>
+ <!-- TODO replace with car support lib sizes when available -->
+ <dimen name="car_fullscreen_user_pod_icon_text_size">32sp</dimen>
+ <dimen name="car_fullscreen_user_pod_width">243dp</dimen>
<dimen name="car_fullscreen_user_pod_height">356dp</dimen>
- <dimen name="car_fullscreen_user_pod_name_text_size">40sp</dimen> <!-- B1 -->
- <dimen name="car_fullscreen_user_pod_device_text_size">@dimen/car_body2_size</dimen>
+ <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
+ <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
<dimen name="car_navigation_button_width">64dp</dimen>
<dimen name="car_navigation_bar_width">760dp</dimen>
diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml
index a462576..7513fd4 100644
--- a/packages/SystemUI/res/values/integers_car.xml
+++ b/packages/SystemUI/res/values/integers_car.xml
@@ -17,4 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<integer name="car_user_switcher_anim_cascade_delay_ms">27</integer>
+ <!-- Full screen user switcher column number TODO: move to support library-->
+ <integer name="user_fullscreen_switcher_num_col">3</integer>
</resources>
diff --git a/packages/SystemUI/res/values/strings_car.xml b/packages/SystemUI/res/values/strings_car.xml
index 658eb4f..0b57ff8 100644
--- a/packages/SystemUI/res/values/strings_car.xml
+++ b/packages/SystemUI/res/values/strings_car.xml
@@ -17,6 +17,10 @@
*/
-->
<resources>
- <string name="unknown_user_label">Unknown</string>
- <string name="start_driving">Start Driving</string>
+ <!-- Name of Guest Profile. [CHAR LIMIT=30] -->
+ <string name="car_guest">Guest</string>
+ <!-- Name of Add User Profile. [CHAR LIMIT=30] -->
+ <string name="car_add_user">Add User</string>
+ <!-- Default name of the new user created. [CHAR LIMIT=30] -->
+ <string name="car_new_user">New User</string>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
index 6fa7db3..32e4bbf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
@@ -18,23 +18,24 @@
import android.app.AppGlobals;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.RemoteException;
-import java.util.ArrayList;
import java.util.List;
public class PackageManagerWrapper {
- private static final String TAG = "PackageManagerWrapper";
-
private static final PackageManagerWrapper sInstance = new PackageManagerWrapper();
private static final IPackageManager mIPackageManager = AppGlobals.getPackageManager();
+ public static final String ACTION_PREFERRED_ACTIVITY_CHANGED =
+ Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
+
public static PackageManagerWrapper getInstance() {
return sInstance;
}
@@ -53,40 +54,15 @@
}
/**
- * @return true if the packageName belongs to the current preferred home app on the device.
- *
- * If will also return false if there are multiple home apps and the user has not picked any
- * preferred home, in which case the user would see a disambiguation screen on going to home.
+ * Report the set of 'Home' activity candidates, plus (if any) which of them
+ * is the current "always use this one" setting.
*/
- public boolean isDefaultHomeActivity(String packageName) {
- List<ResolveInfo> allHomeCandidates = new ArrayList<>();
- ComponentName home;
+ public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
try {
- home = mIPackageManager.getHomeActivities(allHomeCandidates);
+ return mIPackageManager.getHomeActivities(allHomeCandidates);
} catch (RemoteException e) {
e.printStackTrace();
- return false;
+ return null;
}
-
- if (home != null && packageName.equals(home.getPackageName())) {
- return true;
- }
-
- // Find the launcher with the highest priority and return that component if there are no
- // other home activity with the same priority.
- int lastPriority = Integer.MIN_VALUE;
- ComponentName lastComponent = null;
- final int size = allHomeCandidates.size();
- for (int i = 0; i < size; i++) {
- final ResolveInfo ri = allHomeCandidates.get(i);
- if (ri.priority > lastPriority) {
- lastComponent = ri.activityInfo.getComponentName();
- lastPriority = ri.priority;
- } else if (ri.priority == lastPriority) {
- // Two components found with same priority.
- lastComponent = null;
- }
- }
- return lastComponent != null && packageName.equals(lastComponent.getPackageName());
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
index c82c519..9975c41 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
@@ -101,6 +101,11 @@
return this;
}
+ public TransactionCompat setEarlyWakeup() {
+ mTransaction.setEarlyWakeup();
+ return this;
+ }
+
public TransactionCompat setColor(SurfaceControlCompat surfaceControl, float[] color) {
mTransaction.setColor(surfaceControl.mSurfaceControl, color);
return this;
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a4f8d8c..b8a57bf 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -444,13 +444,7 @@
final Surface surface = getSurfaceHolder().getSurface();
surface.hwuiDestroy();
- mLoader = new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- mWallpaperManager.forgetLoadedWallpaper();
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ mWallpaperManager.forgetLoadedWallpaper();
}
private void scheduleUnloadWallpaper() {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index a70b358..40ce69b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -514,7 +514,7 @@
autoTriggerThreshold = 15;
}
- BatterySaverUtils.scheduleAutoBatterySaver(mContext, autoTriggerThreshold);
+ BatterySaverUtils.ensureAutoBatterySaver(mContext, autoTriggerThreshold);
showAutoSaverEnabledConfirmation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
index 23d3ebbb..24b5a34 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
@@ -29,7 +29,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSPanel;
-import com.android.systemui.statusbar.car.UserGridView;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 0ee6d1f..da21aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -20,21 +20,20 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Fragment;
+import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.GridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFooter;
-import com.android.systemui.statusbar.car.PageIndicator;
-import com.android.systemui.statusbar.car.UserGridView;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.car.UserGridRecyclerView;
import java.util.ArrayList;
import java.util.List;
@@ -45,14 +44,12 @@
* status bar, and a static row with access to the user switcher and settings.
*/
public class CarQSFragment extends Fragment implements QS {
- private ViewGroup mPanel;
private View mHeader;
private View mUserSwitcherContainer;
private CarQSFooter mFooter;
private View mFooterUserName;
private View mFooterExpandIcon;
- private UserGridView mUserGridView;
- private PageIndicator mPageIndicator;
+ private UserGridRecyclerView mUserGridView;
private AnimatorSet mAnimatorSet;
private UserSwitchCallback mUserSwitchCallback;
@@ -65,7 +62,6 @@
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mPanel = (ViewGroup) view;
mHeader = view.findViewById(R.id.header);
mFooter = view.findViewById(R.id.qs_footer);
mFooterUserName = mFooter.findViewById(R.id.user_name);
@@ -75,16 +71,15 @@
updateUserSwitcherHeight(0);
- mUserGridView = view.findViewById(R.id.user_grid);
- mUserGridView.init(null, Dependency.get(UserSwitcherController.class),
- false /* overrideAlpha */);
-
- mPageIndicator = view.findViewById(R.id.user_switcher_page_indicator);
- mPageIndicator.setupWithViewPager(mUserGridView);
+ Context context = getContext();
+ mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
+ GridLayoutManager layoutManager = new GridLayoutManager(context,
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.buildAdapter();
mUserSwitchCallback = new UserSwitchCallback();
mFooter.setUserSwitchCallback(mUserSwitchCallback);
- mUserGridView.setUserSwitchCallback(mUserSwitchCallback);
}
@Override
@@ -111,13 +106,11 @@
@Override
public void setHeaderListening(boolean listening) {
mFooter.setListening(listening);
- mUserGridView.setListening(listening);
}
@Override
public void setListening(boolean listening) {
mFooter.setListening(listening);
- mUserGridView.setListening(listening);
}
@Override
@@ -219,24 +212,6 @@
mShowing = false;
animateHeightChange(false /* opening */);
}
-
- public void resetShowing() {
- if (mShowing) {
- for (int i = 0; i < mUserGridView.getChildCount(); i++) {
- ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i);
- // Need to bring the last child to the front to maintain the order in the pod
- // container. Why? ¯\_(ツ)_/¯
- if (podContainer.getChildCount() > 0) {
- podContainer.getChildAt(podContainer.getChildCount() - 1).bringToFront();
- }
- // The alpha values are default to 0, so if the pods have been refreshed, they
- // need to be set to 1 when showing.
- for (int j = 0; j < podContainer.getChildCount(); j++) {
- podContainer.getChildAt(j).setAlpha(1f);
- }
- }
- }
- }
}
private void updateUserSwitcherHeight(int height) {
@@ -260,27 +235,6 @@
});
allAnimators.add(heightAnimator);
- // The user grid contains pod containers that each contain a number of pods. Animate
- // all pods to avoid any discrepancy/race conditions with possible changes during the
- // animation.
- int cascadeDelay = getResources().getInteger(
- R.integer.car_user_switcher_anim_cascade_delay_ms);
- for (int i = 0; i < mUserGridView.getChildCount(); i++) {
- ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i);
- for (int j = 0; j < podContainer.getChildCount(); j++) {
- View pod = podContainer.getChildAt(j);
- Animator podAnimator = AnimatorInflater.loadAnimator(getContext(),
- opening ? R.anim.car_user_switcher_open_pod_animation
- : R.anim.car_user_switcher_close_pod_animation);
- // Add the cascading delay between pods
- if (opening) {
- podAnimator.setStartDelay(podAnimator.getStartDelay() + j * cascadeDelay);
- }
- podAnimator.setTarget(pod);
- allAnimators.add(podAnimator);
- }
- }
-
Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(),
opening ? R.anim.car_user_switcher_open_name_animation
: R.anim.car_user_switcher_close_name_animation);
@@ -293,12 +247,6 @@
iconAnimator.setTarget(mFooterExpandIcon);
allAnimators.add(iconAnimator);
- Animator pageAnimator = AnimatorInflater.loadAnimator(getContext(),
- opening ? R.anim.car_user_switcher_open_pages_animation
- : R.anim.car_user_switcher_close_pages_animation);
- pageAnimator.setTarget(mPageIndicator);
- allAnimators.add(pageAnimator);
-
mAnimatorSet = new AnimatorSet();
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 28917ab..f7cbee6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -210,7 +210,7 @@
state.slash.isSlashed = !state.value;
state.label = getTileLabel();
state.secondaryLabel = ZenModeConfig.getDescription(mContext,zen != Global.ZEN_MODE_OFF,
- mController.getConfig());
+ mController.getConfig(), false);
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index b81e9af..29c2edc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -26,6 +26,7 @@
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
@@ -1631,6 +1632,42 @@
return null;
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ float y = ev.getY();
+ // We still want to distribute touch events to the remote input even if it's outside the
+ // view boundary. We're therefore manually dispatching these events to the remote view
+ RemoteInputView riv = getRemoteInputForView(getViewForVisibleType(mVisibleType));
+ if (riv != null && riv.getVisibility() == VISIBLE) {
+ int inputStart = mUnrestrictedContentHeight - riv.getHeight();
+ if (y <= mUnrestrictedContentHeight && y >= inputStart) {
+ ev.offsetLocation(0, -inputStart);
+ return riv.dispatchTouchEvent(ev);
+ }
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
+ /**
+ * Overridden to make sure touches to the reply action bar actually go through to this view
+ */
+ @Override
+ public boolean pointInView(float localX, float localY, float slop) {
+ float top = mClipTopAmount;
+ float bottom = mUnrestrictedContentHeight;
+ return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
+ localY < (bottom + slop);
+ }
+
+ private RemoteInputView getRemoteInputForView(View child) {
+ if (child == mExpandedChild) {
+ return mExpandedRemoteInput;
+ } else if (child == mHeadsUpChild) {
+ return mHeadsUpRemoteInput;
+ }
+ return null;
+ }
+
public int getExpandHeight() {
int viewType = VISIBLE_TYPE_EXPANDED;
if (mExpandedChild == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 852239a..abc261e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -172,6 +172,14 @@
}
}
+ if (mediaNotification != null) {
+ mMediaNotificationKey = mediaNotification.notification.getKey();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ + mMediaNotificationKey + " controller=" + mMediaController);
+ }
+ }
+
if (controller != null && !sameSessions(mMediaController, controller)) {
// We have a new media session
clearCurrentMediaNotification();
@@ -183,13 +191,6 @@
+ mMediaMetadata);
}
- if (mediaNotification != null) {
- mMediaNotificationKey = mediaNotification.notification.getKey();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
- + mMediaNotificationKey + " controller=" + mMediaController);
- }
- }
metaDataChanged = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index e248db4..ec243fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -24,8 +24,8 @@
private String mLongIntent;
private boolean mBroadcastIntent;
private boolean mSelected = false;
- private float mSelectedAlpha;
- private float mUnselectedAlpha;
+ private float mSelectedAlpha = 1f;
+ private float mUnselectedAlpha = 1f;
private int mSelectedIconResourceId;
private int mIconResourceId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3fb1137..008794c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -418,8 +418,7 @@
Dependency.get(UserSwitcherController.class);
if (userSwitcherController.useFullscreenUserSwitcher()) {
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
- userSwitcherController,
- mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
+ mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
} else {
super.createUserSwitcher();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index bc353f2..fb525f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,14 +18,15 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.content.res.Resources;
+import android.content.Context;
import android.view.View;
import android.view.ViewStub;
import android.widget.ProgressBar;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
* Manages the fullscreen user switcher.
@@ -33,36 +34,25 @@
public class FullscreenUserSwitcher {
private final View mContainer;
private final View mParent;
- private final UserGridView mUserGridView;
- private final UserSwitcherController mUserSwitcherController;
+ private final UserGridRecyclerView mUserGridView;
private final ProgressBar mSwitchingUsers;
private final int mShortAnimDuration;
private boolean mShowing;
- public FullscreenUserSwitcher(StatusBar statusBar,
- UserSwitcherController userSwitcherController,
- ViewStub containerStub) {
- mUserSwitcherController = userSwitcherController;
+ public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) {
mParent = containerStub.inflate();
mContainer = mParent.findViewById(R.id.container);
mUserGridView = mContainer.findViewById(R.id.user_grid);
- mUserGridView.init(statusBar, mUserSwitcherController, true /* overrideAlpha */);
- mUserGridView.setUserSelectionListener(record -> {
- if (!record.isCurrent) {
- toggleSwitchInProgress(true);
- }
- });
+ mUserGridView.setStatusBar(statusBar);
+ GridLayoutManager layoutManager = new GridLayoutManager(context,
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.buildAdapter();
+ mUserGridView.setUserSelectionListener(record -> toggleSwitchInProgress(true));
- PageIndicator pageIndicator = mContainer.findViewById(R.id.user_switcher_page_indicator);
- pageIndicator.setupWithViewPager(mUserGridView);
-
- Resources res = mContainer.getResources();
- mShortAnimDuration = res.getInteger(android.R.integer.config_shortAnimTime);
-
- mContainer.findViewById(R.id.start_driving).setOnClickListener(v -> {
- automaticallySelectUser();
- });
+ mShortAnimDuration = mContainer.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
mSwitchingUsers = mParent.findViewById(R.id.switching_users);
}
@@ -115,10 +105,4 @@
toggleSwitchInProgress(false);
mParent.setVisibility(View.GONE);
}
-
- private void automaticallySelectUser() {
- // TODO: Switch according to some policy. This implementation just tries to drop the
- // keyguard for the current user.
- mUserGridView.showOfflineAuthUi();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
new file mode 100644
index 0000000..e09a360
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.car;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.GradientDrawable;
+import android.os.AsyncTask;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.settingslib.users.UserManagerHelper;
+import com.android.systemui.R;
+import com.android.systemui.qs.car.CarQSFragment;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Displays a GridLayout with icons for the users in the system to allow switching between users.
+ * One of the uses of this is for the lock screen in auto.
+ */
+public class UserGridRecyclerView extends RecyclerView implements
+ UserManagerHelper.OnUsersUpdateListener {
+
+ private StatusBar mStatusBar;
+ private UserSelectionListener mUserSelectionListener;
+ private UserAdapter mAdapter;
+ private UserManagerHelper mUserManagerHelper;
+ private Context mContext;
+
+ public UserGridRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ super.setHasFixedSize(true);
+ mContext = context;
+ mUserManagerHelper = new UserManagerHelper(mContext);
+ }
+
+ /**
+ * Register listener for any update to the users
+ */
+ @Override
+ public void onFinishInflate() {
+ mUserManagerHelper.registerOnUsersUpdateListener(this);
+ }
+
+ /**
+ * Unregisters listener checking for any change to the users
+ */
+ @Override
+ public void onDetachedFromWindow() {
+ mUserManagerHelper.unregisterOnUsersUpdateListener();
+ }
+
+ /**
+ * Initializes the adapter that populates the grid layout
+ *
+ * @return the adapter
+ */
+ public void buildAdapter() {
+ List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
+ .getAllUsers());
+ mAdapter = new UserAdapter(mContext, userRecords);
+ super.setAdapter(mAdapter);
+ }
+
+ public void setStatusBar(@Nullable StatusBar statusBar) {
+ mStatusBar = statusBar;
+ }
+
+ private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
+ List<UserRecord> userRecords = new ArrayList<>();
+ for (UserInfo userInfo : userInfoList) {
+ boolean isCurrent = false;
+ if (ActivityManager.getCurrentUser() == userInfo.id) {
+ isCurrent = true;
+ }
+ UserRecord record = new UserRecord(userInfo, false /* isGuest */,
+ false /* isAddUser */, isCurrent);
+ userRecords.add(record);
+ }
+
+ // Add guest user record if the current user is not a guest
+ if (!mUserManagerHelper.isGuestUser()) {
+ userRecords.add(addGuestUserRecord());
+ }
+
+ // Add add user record if the current user can add users
+ if (mUserManagerHelper.canAddUsers()) {
+ userRecords.add(addUserRecord());
+ }
+
+ return userRecords;
+ }
+
+ /**
+ * Create guest user record
+ */
+ private UserRecord addGuestUserRecord() {
+ UserInfo userInfo = new UserInfo();
+ userInfo.name = mContext.getString(R.string.car_guest);
+ return new UserRecord(userInfo, true /* isGuest */,
+ false /* isAddUser */, false /* isCurrent */);
+ }
+
+ /**
+ * Create add user record
+ */
+ private UserRecord addUserRecord() {
+ UserInfo userInfo = new UserInfo();
+ userInfo.name = mContext.getString(R.string.car_add_user);
+ return new UserRecord(userInfo, false /* isGuest */,
+ true /* isAddUser */, false /* isCurrent */);
+ }
+
+ public void onUserSwitched(int newUserId) {
+ // Bring up security view after user switch is completed.
+ post(this::showOfflineAuthUi);
+ }
+
+ public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
+ mUserSelectionListener = userSelectionListener;
+ }
+
+ void showOfflineAuthUi() {
+ // TODO: Show keyguard UI in-place.
+ if (mStatusBar != null) {
+ mStatusBar.executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ }
+ }
+
+ @Override
+ public void onUsersUpdate() {
+ mAdapter.clearUsers();
+ mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
+ mAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Adapter to populate the grid layout with the available user profiles
+ */
+ public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder> {
+
+ private final Context mContext;
+ private List<UserRecord> mUsers;
+ private final int mPodImageAvatarWidth;
+ private final int mPodImageAvatarHeight;
+ private final Resources mRes;
+ private final String mGuestName;
+ private final String mNewUserName;
+
+ public UserAdapter(Context context, List<UserRecord> users) {
+ mRes = context.getResources();
+ mContext = context;
+ updateUsers(users);
+ mPodImageAvatarWidth = mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_image_avatar_width);
+ mPodImageAvatarHeight = mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_image_avatar_height);
+ mGuestName = mRes.getString(R.string.car_guest);
+ mNewUserName = mRes.getString(R.string.car_new_user);
+ }
+
+ public void clearUsers() {
+ mUsers.clear();
+ }
+
+ public void updateUsers(List<UserRecord> users) {
+ mUsers = users;
+ }
+
+ @Override
+ public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.car_fullscreen_user_pod, parent, false);
+ view.setAlpha(1f);
+ view.bringToFront();
+ return new UserAdapterViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
+ UserRecord userRecord = mUsers.get(position);
+ holder.mUserAvatarImageView.setImageBitmap(getDefaultUserIcon(userRecord));
+ holder.mUserNameTextView.setText(userRecord.mInfo.name);
+ holder.mView.setOnClickListener(v -> {
+ if (userRecord == null) {
+ return;
+ }
+
+ // Notify the listener which user was selected
+ if (mUserSelectionListener != null) {
+ mUserSelectionListener.onUserSelected(userRecord);
+ }
+
+ // If the user selects Guest, switch to Guest profile
+ if (userRecord.mIsGuest) {
+ mUserManagerHelper.switchToGuest(mGuestName);
+ return;
+ }
+
+ // If the user wants to add a user, start task to add new user
+ if (userRecord.mIsAddUser) {
+ new AddNewUserTask().execute(mNewUserName);
+ return;
+ }
+
+ // If the user doesn't want to be a guest or add a user, switch to the user selected
+ mUserManagerHelper.switchToUser(userRecord.mInfo);
+ });
+
+ }
+
+ private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
+
+ @Override
+ protected UserInfo doInBackground(String... userNames) {
+ return mUserManagerHelper.createNewUser(userNames[0]);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ }
+
+ @Override
+ protected void onPostExecute(UserInfo user) {
+ if (user != null) {
+ mUserManagerHelper.switchToUser(user);
+ }
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mUsers.size();
+ }
+
+ /**
+ * Returns the default user icon. This icon is a circle with a letter in it. The letter is
+ * the first character in the username.
+ *
+ * @param record the profile of the user for which the icon should be created
+ */
+ private Bitmap getDefaultUserIcon(UserRecord record) {
+ CharSequence displayText;
+ boolean isAddUserText = false;
+ if (record.mIsAddUser) {
+ displayText = "+";
+ isAddUserText = true;
+ } else {
+ displayText = record.mInfo.name.subSequence(0, 1);
+ }
+ Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(out);
+
+ // Draw the circle background.
+ GradientDrawable shape = new GradientDrawable();
+ shape.setShape(GradientDrawable.RADIAL_GRADIENT);
+ shape.setGradientRadius(1.0f);
+ shape.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_bgcolor));
+ shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
+ shape.draw(canvas);
+
+ // Draw the letter in the center.
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_fgcolor));
+ paint.setTextAlign(Align.CENTER);
+ if (isAddUserText) {
+ paint.setTextSize(mRes.getDimensionPixelSize(
+ R.dimen.car_touch_target_size));
+ } else {
+ paint.setTextSize(mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_icon_text_size));
+ }
+
+ Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
+ // The Y coordinate is measured by taking half the height of the pod, but that would
+ // draw the character putting the bottom of the font in the middle of the pod. To
+ // correct this, half the difference between the top and bottom distance metrics of the
+ // font gives the offset of the font. Bottom is a positive value, top is negative, so
+ // the different is actually a sum. The "half" operation is then factored out.
+ canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
+ (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
+
+ return out;
+ }
+
+ public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
+
+ public ImageView mUserAvatarImageView;
+ public TextView mUserNameTextView;
+ public View mView;
+
+ public UserAdapterViewHolder(View view) {
+ super(view);
+ mView = view;
+ mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
+ mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
+ }
+ }
+ }
+
+ /**
+ * Object wrapper class for the userInfo. Use it to distinguish if a profile is a
+ * guest profile, add user profile, or a current user.
+ */
+ public static final class UserRecord {
+
+ public final UserInfo mInfo;
+ public final boolean mIsGuest;
+ public final boolean mIsAddUser;
+ public final boolean mIsCurrent;
+
+ public UserRecord(UserInfo userInfo, boolean isGuest, boolean isAddUser,
+ boolean isCurrent) {
+ mInfo = userInfo;
+ mIsGuest = isGuest;
+ mIsAddUser = isAddUser;
+ mIsCurrent = isCurrent;
+ }
+ }
+
+ /**
+ * Listener used to notify when a user has been selected
+ */
+ interface UserSelectionListener {
+
+ void onUserSelected(UserRecord record);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
deleted file mode 100644
index 1bd820d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.car;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.qs.car.CarQSFragment;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Vector;
-
-/**
- * Displays a ViewPager with icons for the users in the system to allow switching between users.
- * One of the uses of this is for the lock screen in auto.
- */
-public class UserGridView extends ViewPager implements
- UserInfoController.OnUserInfoChangedListener {
- private StatusBar mStatusBar;
- private UserSwitcherController mUserSwitcherController;
- private Adapter mAdapter;
- private UserSelectionListener mUserSelectionListener;
- private UserInfoController mUserInfoController;
- private Vector mUserContainers;
- private int mContainerWidth;
- private boolean mOverrideAlpha;
- private CarQSFragment.UserSwitchCallback mUserSwitchCallback;
-
- public UserGridView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
- boolean overrideAlpha) {
- mStatusBar = statusBar;
- mUserSwitcherController = userSwitcherController;
- mAdapter = new Adapter(mUserSwitcherController);
- mUserInfoController = Dependency.get(UserInfoController.class);
- mOverrideAlpha = overrideAlpha;
- // Whenever the container width changes, the containers must be refreshed. Instead of
- // doing an initial refreshContainers() to populate the containers, this listener will
- // refresh them on layout change because that affects how the users are split into
- // containers. Furthermore, at this point, the container width is unknown, so
- // refreshContainers() cannot populate any containers.
- addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- int newWidth = Math.max(left - right, right - left);
- if (mContainerWidth != newWidth) {
- mContainerWidth = newWidth;
- refreshContainers();
- }
- });
- }
-
- private void refreshContainers() {
- mUserContainers = new Vector();
-
- Context context = getContext();
- LayoutInflater inflater = LayoutInflater.from(context);
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup pods = (ViewGroup) inflater.inflate(
- R.layout.car_fullscreen_user_pod_container, null);
-
- int iconsPerPage = mAdapter.getIconsPerPage();
- int limit = Math.min(mUserSwitcherController.getUsers().size(), (i + 1) * iconsPerPage);
- for (int j = i * iconsPerPage; j < limit; j++) {
- View v = mAdapter.makeUserPod(inflater, context, j, pods);
- if (mOverrideAlpha) {
- v.setAlpha(1f);
- }
- pods.addView(v);
- // This is hacky, but the dividers on the pod container LinearLayout don't seem
- // to work for whatever reason. Instead, set a right margin on the pod if it's not
- // the right-most pod and there is more than one pod in the container.
- if (i < limit - 1 && limit > 1) {
- ViewGroup.MarginLayoutParams params =
- (ViewGroup.MarginLayoutParams) v.getLayoutParams();
- params.setMargins(0, 0, getResources().getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_margin_between), 0);
- v.setLayoutParams(params);
- }
- }
- mUserContainers.add(pods);
- }
-
- mAdapter = new Adapter(mUserSwitcherController);
- setAdapter(mAdapter);
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
- refreshContainers();
- }
-
- public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) {
- mUserSwitchCallback = callback;
- }
-
- public void onUserSwitched(int newUserId) {
- // Bring up security view after user switch is completed.
- post(this::showOfflineAuthUi);
- }
-
- public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
- mUserSelectionListener = userSelectionListener;
- }
-
- public void setListening(boolean listening) {
- if (listening) {
- mUserInfoController.addCallback(this);
- } else {
- mUserInfoController.removeCallback(this);
- }
- }
-
- void showOfflineAuthUi() {
- // TODO: Show keyguard UI in-place.
- mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true, true);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
- int height = 0;
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
- height = MeasureSpec.getSize(heightMeasureSpec);
- } else {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- child.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- height = Math.max(child.getMeasuredHeight(), height);
- }
-
- // Respect the AT_MOST request from parent.
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
- height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height);
- }
- }
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- /**
- * This is a ViewPager.PagerAdapter which deletegates the work to a
- * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have
- * to use composition instead to achieve the same goal since both the base classes are abstract
- * classes and not interfaces.
- */
- private final class Adapter extends PagerAdapter {
- private final int mPodWidth;
- private final int mPodMarginBetween;
- private final int mPodImageAvatarWidth;
- private final int mPodImageAvatarHeight;
-
- private final WrappedBaseUserAdapter mUserAdapter;
-
- public Adapter(UserSwitcherController controller) {
- super();
- mUserAdapter = new WrappedBaseUserAdapter(controller, this);
-
- Resources res = getResources();
- mPodWidth = res.getDimensionPixelSize(R.dimen.car_fullscreen_user_pod_width);
- mPodMarginBetween = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_margin_between);
- mPodImageAvatarWidth = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_width);
- mPodImageAvatarHeight = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_height);
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View) object);
- }
-
- private int getIconsPerPage() {
- // We need to know how many pods we need in this page. Each pod has its own width and
- // a margin between them. We can then divide the measured width of the parent by the
- // sum of pod width and margin to get the number of pods that will completely fit.
- // There is one less margin than the number of pods (eg. for 5 pods, there are 4
- // margins), so need to add the margin to the measured width to account for that.
- return (mContainerWidth + mPodMarginBetween) /
- (mPodWidth + mPodMarginBetween);
- }
-
- @Override
- public void finishUpdate(ViewGroup container) {
- if (mUserSwitchCallback != null) {
- mUserSwitchCallback.resetShowing();
- }
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- if (position < mUserContainers.size()) {
- container.addView((View) mUserContainers.get(position));
- return mUserContainers.get(position);
- } else {
- return null;
- }
- }
-
- /**
- * Returns the default user icon. This icon is a circle with a letter in it. The letter is
- * the first character in the username.
- *
- * @param userName the username of the user for which the icon is to be created
- */
- private Bitmap getDefaultUserIcon(CharSequence userName) {
- CharSequence displayText = userName.subSequence(0, 1);
- Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(out);
-
- // Draw the circle background.
- GradientDrawable shape = new GradientDrawable();
- shape.setShape(GradientDrawable.RADIAL_GRADIENT);
- shape.setGradientRadius(1.0f);
- shape.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_bgcolor));
- shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
- shape.draw(canvas);
-
- // Draw the letter in the center.
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_fgcolor));
- paint.setTextAlign(Align.CENTER);
- paint.setTextSize(getResources().getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_icon_text_size));
- Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
- // The Y coordinate is measured by taking half the height of the pod, but that would
- // draw the character putting the bottom of the font in the middle of the pod. To
- // correct this, half the difference between the top and bottom distance metrics of the
- // font gives the offset of the font. Bottom is a positive value, top is negative, so
- // the different is actually a sum. The "half" operation is then factored out.
- canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
- (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
-
- return out;
- }
-
- private View makeUserPod(LayoutInflater inflater, Context context,
- int position, ViewGroup parent) {
- final UserSwitcherController.UserRecord record = mUserAdapter.getItem(position);
- View view = inflater.inflate(R.layout.car_fullscreen_user_pod, parent, false);
-
- TextView nameView = view.findViewById(R.id.user_name);
- if (record != null) {
- nameView.setText(mUserAdapter.getName(context, record));
- view.setActivated(record.isCurrent);
- } else {
- nameView.setText(context.getString(R.string.unknown_user_label));
- }
-
- ImageView iconView = (ImageView) view.findViewById(R.id.user_avatar);
- if (record == null || (record.picture == null && !record.isAddUser)) {
- iconView.setImageBitmap(getDefaultUserIcon(nameView.getText()));
- } else if (record.isAddUser) {
- Drawable icon = context.getDrawable(R.drawable.ic_add_circle_qs);
- icon.setTint(context.getColor(R.color.car_user_switcher_no_user_image_bgcolor));
- iconView.setImageDrawable(icon);
- } else {
- iconView.setImageBitmap(record.picture);
- }
-
- iconView.setOnClickListener(v -> {
- if (record == null) {
- return;
- }
-
- if (mUserSelectionListener != null) {
- mUserSelectionListener.onUserSelected(record);
- }
-
- if (record.isCurrent) {
- showOfflineAuthUi();
- } else {
- mUserSwitcherController.switchTo(record);
- }
- });
-
- return view;
- }
-
- @Override
- public int getCount() {
- int iconsPerPage = getIconsPerPage();
- if (iconsPerPage == 0) {
- return 0;
- }
- return (int) Math.ceil((double) mUserAdapter.getCount() / getIconsPerPage());
- }
-
- public void refresh() {
- mUserAdapter.refresh();
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
- }
- }
-
- private final class WrappedBaseUserAdapter extends UserSwitcherController.BaseUserAdapter {
- private final Adapter mContainer;
-
- public WrappedBaseUserAdapter(UserSwitcherController controller, Adapter container) {
- super(controller);
- mContainer = container;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- throw new UnsupportedOperationException("unused");
- }
-
- @Override
- public void notifyDataSetChanged() {
- super.notifyDataSetChanged();
- mContainer.notifyDataSetChanged();
- }
- }
-
- interface UserSelectionListener {
- void onUserSelected(UserSwitcherController.UserRecord record);
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 3bbfe3c..b8bce95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -238,6 +238,7 @@
t.deferTransactionUntilSurface(app.leash, systemUiSurface,
systemUiSurface.getNextFrameNumber());
}
+ t.setEarlyWakeup();
t.apply();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3dbac51..2c335a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -196,6 +196,9 @@
}
mState = ScrimState.UNINITIALIZED;
+ mScrimBehind.setDefaultFocusHighlightEnabled(false);
+ mScrimInFront.setDefaultFocusHighlightEnabled(false);
+
updateScrims();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index d38c083..bbdaa99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -112,9 +112,9 @@
mCurrentInFrontTint = Color.BLACK;
mCurrentBehindTint = Color.BLACK;
mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
- // DisplayPowerManager will blank the screen for us, we just need
- // to set our state.
- mAnimateChange = !mDisplayRequiresBlanking;
+ // DisplayPowerManager may blank the screen for us,
+ // in this case we just need to set our state.
+ mAnimateChange = mDozeParameters.shouldControlScreenOff();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7987bfd..aa9bbe08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3899,7 +3899,11 @@
}
public boolean onBackPressed() {
- if (mStatusBarKeyguardViewManager.onBackPressed()) {
+ boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
+ if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
+ if (!isScrimmedBouncer) {
+ mNotificationPanel.expandWithoutQs();
+ }
return true;
}
if (mNotificationPanel.isQsExpanded()) {
@@ -4994,6 +4998,14 @@
@Override
public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
+ RemoteInputController controller = mRemoteInputManager.getController();
+ if (controller.isRemoteInputActive(row.getEntry())
+ && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
+ // We have an active remote input typed and the user clicked on the notification.
+ // this was probably unintentional, so we're closing the edit text instead.
+ controller.closeRemoteInputs();
+ return;
+ }
Notification notification = sbn.getNotification();
final PendingIntent intent = notification.contentIntent != null
? notification.contentIntent
@@ -5057,12 +5069,7 @@
Intent fillInIntent = null;
Entry entry = row.getEntry();
CharSequence remoteInputText = null;
- RemoteInputController controller = mRemoteInputManager.getController();
- if (controller.isRemoteInputActive(entry)) {
- remoteInputText = row.getActiveRemoteInputText();
- }
- if (TextUtils.isEmpty(remoteInputText)
- && !TextUtils.isEmpty(entry.remoteInputText)) {
+ if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
}
if (!TextUtils.isEmpty(remoteInputText)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 2727b30..670c68f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -512,12 +512,15 @@
/**
* Notifies this manager that the back button has been pressed.
*
+ * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
+ * Non-scrimmed bouncers have a special animation tied to the expansion
+ * of the notification panel.
* @return whether the back press has been handled
*/
- public boolean onBackPressed() {
+ public boolean onBackPressed(boolean hideImmediately) {
if (mBouncer.isShowing()) {
mStatusBar.endAffordanceLaunch();
- reset(true /* hideBouncerWhenShowing */);
+ reset(hideImmediately);
return true;
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 13157fe..a2d2615 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -212,7 +212,6 @@
.setDuration(300)
.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
.withEndAction(() -> {
- mWindow.getDecorView().requestAccessibilityFocus();
if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
mRingerIcon.postOnAnimationDelayed(mSinglePress, 1500);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1e8e14d..82129a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -246,7 +246,7 @@
}
@Test
- public void scrimBlanksBeforeLeavingAoD() {
+ public void scrimBlanksBeforeLeavingAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
mScrimController.finishAnimationsImmediately();
@@ -455,6 +455,28 @@
}
}
+ @Test
+ public void testAnimatesTransitionToAod() {
+ when(mDozeParamenters.shouldControlScreenOff()).thenReturn(false);
+ ScrimState.AOD.prepare(ScrimState.KEYGUARD);
+ Assert.assertFalse("No animation when ColorFade kicks in",
+ ScrimState.AOD.getAnimateChange());
+
+ reset(mDozeParamenters);
+ when(mDozeParamenters.shouldControlScreenOff()).thenReturn(true);
+ ScrimState.AOD.prepare(ScrimState.KEYGUARD);
+ Assert.assertTrue("Animate scrims when ColorFade won't be triggered",
+ ScrimState.AOD.getAnimateChange());
+ }
+
+ @Test
+ public void testViewsDontHaveFocusHighlight() {
+ Assert.assertFalse("Scrim shouldn't have focus highlight",
+ mScrimInFront.getDefaultFocusHighlightEnabled());
+ Assert.assertFalse("Scrim shouldn't have focus highlight",
+ mScrimBehind.getDefaultFocusHighlightEnabled());
+ }
+
/**
* Conserves old notification density after leaving state and coming back.
*
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0ee026e..739b716 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5578,6 +5578,11 @@
// OS: P
WIFI_SCANNING_NEEDED_DIALOG = 1373;
+ // OPEN: Settings > System > Gestures > Swipe up gesture
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_GESTURE_SWIPE_UP = 1374;
+
// ---- End P Constants, all P constants go above this line ----
// First Q constant in master goes here:
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index e05416e..595a1d9 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -422,6 +422,16 @@
// Indicates the number of times a scan request from an external background app was throttled.
optional int32 num_external_background_app_oneshot_scan_requests_throttled = 106;
+
+ // WifiLastResortWatchdog time milliseconds delta between trigger and first connection success
+ optional int64 watchdog_trigger_to_connection_success_duration_ms = 107 [default = -1];
+
+ // The number of times wifi experienced failures after watchdog has already been triggered and is
+ // waiting for a connection success
+ optional int64 watchdog_total_connection_failure_count_after_trigger = 108;
+
+ // Number of times DFS channel scans are requested in single scan requests.
+ optional int32 num_oneshot_has_dfs_channel_scans = 109;
}
// Information that gets logged for every WiFi connection.
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3dc2323..655dbef 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -99,6 +99,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -1971,8 +1972,8 @@
return;
}
- if (value != null && !value.equals(viewState.getCurrentValue())) {
- if (value.isEmpty()
+ if (!Objects.equals(value, viewState.getCurrentValue())) {
+ if ((value == null || value.isEmpty())
&& viewState.getCurrentValue() != null
&& viewState.getCurrentValue().isText()
&& viewState.getCurrentValue().getTextValue() != null
@@ -1993,18 +1994,26 @@
// Must check if this update was caused by autofilling the view, in which
// case we just update the value, but not the UI.
final AutofillValue filledValue = viewState.getAutofilledValue();
- if (value.equals(filledValue)) {
+ if (filledValue != null && filledValue.equals(value)) {
+ if (sVerbose) {
+ Slog.v(TAG, "ignoring autofilled change on id " + id);
+ }
return;
}
// Update the internal state...
viewState.setState(ViewState.STATE_CHANGED);
//..and the UI
- if (value.isText()) {
- getUiForShowing().filterFillUi(value.getTextValue().toString(), this);
+ final String filterText;
+ if (value == null || !value.isText()) {
+ filterText = null;
} else {
- getUiForShowing().filterFillUi(null, this);
+ final CharSequence text = value.getTextValue();
+ // Text should never be null, but it doesn't hurt to check to avoid a
+ // system crash...
+ filterText = (text == null) ? null : text.toString();
}
+ getUiForShowing().filterFillUi(filterText, this);
}
break;
case ACTION_VIEW_ENTERED:
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f678eed..325dabe 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1404,7 +1404,7 @@
private void resetDefaultImeLocked(Context context) {
// Do not reset the default (current) IME when it is a 3rd-party IME
- if (mCurMethodId != null && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
+ if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
return;
}
final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
@@ -3068,7 +3068,7 @@
: mCurrentSubtype.getLocale();
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = enabled.get(i);
- if (imi.getSubtypeCount() > 0 && InputMethodUtils.isSystemIme(imi)) {
+ if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
InputMethodSubtype keyboardSubtype =
InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
InputMethodUtils.getSubtypes(imi),
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 1d305fb..365c436 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -1255,7 +1255,7 @@
for (int i = 0; i < recentsCount; i++) {
final TaskRecord tr = mTasks.get(i);
if (task != tr) {
- if (!task.hasCompatibleActivityType(tr)) {
+ if (!task.hasCompatibleActivityType(tr) || task.userId != tr.userId) {
continue;
}
final Intent trIntent = tr.intent;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index b7bbb3b..e3d0bdd 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -79,7 +79,7 @@
*/
public final class ContentService extends IContentService.Stub {
static final String TAG = "ContentService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
public static class Lifecycle extends SystemService {
private ContentService mService;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 66817fa..736aa46 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -127,7 +127,7 @@
* Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
* @hide
*/
-public final class JobSchedulerService extends com.android.server.SystemService
+public class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
public static final String TAG = "JobScheduler";
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -781,6 +781,10 @@
}
};
+ public Context getTestableContext() {
+ return getContext();
+ }
+
public Object getLock() {
return mLock;
}
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 8365fd2..0c66c5b 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -30,12 +30,12 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.TrafficStats;
-import android.os.Process;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -46,6 +46,7 @@
import com.android.server.job.JobServiceContext;
import com.android.server.job.StateControllerProto;
+import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -63,7 +64,6 @@
private final ConnectivityManager mConnManager;
private final NetworkPolicyManager mNetPolicyManager;
- private boolean mConnected;
@GuardedBy("mLock")
private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>();
@@ -74,9 +74,11 @@
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- mConnected = false;
+ // We're interested in all network changes; internally we match these
+ // network changes against the active network for each UID with jobs.
+ final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+ mConnManager.registerNetworkCallback(request, mNetworkCallback);
- mConnManager.registerDefaultNetworkCallback(mNetworkCallback);
mNetPolicyManager.registerListener(mNetPolicyListener);
}
@@ -198,14 +200,18 @@
}
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
+ final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
+ final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+ return updateConstraintsSatisfied(jobStatus, network, capabilities);
+ }
+
+ private boolean updateConstraintsSatisfied(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
// TODO: consider matching against non-active networks
- final int jobUid = jobStatus.getSourceUid();
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
-
- final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
- final NetworkInfo info = mConnManager.getNetworkInfoForUid(network, jobUid, ignoreBlocked);
- final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+ final NetworkInfo info = mConnManager.getNetworkInfoForUid(network,
+ jobStatus.getSourceUid(), ignoreBlocked);
final boolean connected = (info != null) && info.isConnected();
final boolean satisfied = isSatisfied(jobStatus, network, capabilities, mConstants);
@@ -218,12 +224,6 @@
// using non-default routes.
jobStatus.network = network;
- // Track system-uid connected/validated as a general reportable proxy for the
- // overall state of connectivity constraint satisfiability.
- if (jobUid == Process.SYSTEM_UID) {
- mConnected = connected;
- }
-
if (DEBUG) {
Slog.i(TAG, "Connectivity " + (changed ? "CHANGED" : "unchanged")
+ " for " + jobStatus + ": connected=" + connected
@@ -233,18 +233,48 @@
}
/**
- * Update all jobs tracked by this controller.
+ * Update any jobs tracked by this controller that match given filters.
*
- * @param uid only update jobs belonging to this UID, or {@code -1} to
+ * @param filterUid only update jobs belonging to this UID, or {@code -1} to
* update all tracked jobs.
+ * @param filterNetwork only update jobs that would use this
+ * {@link Network}, or {@code null} to update all tracked jobs.
*/
- private void updateTrackedJobs(int uid) {
+ private void updateTrackedJobs(int filterUid, Network filterNetwork) {
synchronized (mLock) {
+ // Since this is a really hot codepath, temporarily cache any
+ // answers that we get from ConnectivityManager.
+ final SparseArray<Network> uidToNetwork = new SparseArray<>();
+ final SparseArray<NetworkCapabilities> networkToCapabilities = new SparseArray<>();
+
boolean changed = false;
- for (int i = mTrackedJobs.size()-1; i >= 0; i--) {
+ for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
final JobStatus js = mTrackedJobs.valueAt(i);
- if (uid == -1 || uid == js.getSourceUid()) {
- changed |= updateConstraintsSatisfied(js);
+ final int uid = js.getSourceUid();
+
+ final boolean uidMatch = (filterUid == -1 || filterUid == uid);
+ if (uidMatch) {
+ Network network = uidToNetwork.get(uid);
+ if (network == null) {
+ network = mConnManager.getActiveNetworkForUid(uid);
+ uidToNetwork.put(uid, network);
+ }
+
+ // Update either when we have a network match, or when the
+ // job hasn't yet been evaluated against the currently
+ // active network; typically when we just lost a network.
+ final boolean networkMatch = (filterNetwork == null
+ || Objects.equals(filterNetwork, network));
+ final boolean forceUpdate = !Objects.equals(js.network, network);
+ if (networkMatch || forceUpdate) {
+ final int netId = network != null ? network.netId : -1;
+ NetworkCapabilities capabilities = networkToCapabilities.get(netId);
+ if (capabilities == null) {
+ capabilities = mConnManager.getNetworkCapabilities(network);
+ networkToCapabilities.put(netId, capabilities);
+ }
+ changed |= updateConstraintsSatisfied(js, network, capabilities);
+ }
}
}
if (changed) {
@@ -273,19 +303,19 @@
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
if (DEBUG) {
- Slog.v(TAG, "onCapabilitiesChanged() : " + networkCapabilities);
+ Slog.v(TAG, "onCapabilitiesChanged: " + network);
}
- updateTrackedJobs(-1);
+ updateTrackedJobs(-1, network);
}
@Override
public void onLost(Network network) {
if (DEBUG) {
- Slog.v(TAG, "Network lost");
+ Slog.v(TAG, "onLost: " + network);
}
- updateTrackedJobs(-1);
+ updateTrackedJobs(-1, network);
}
};
@@ -293,25 +323,9 @@
@Override
public void onUidRulesChanged(int uid, int uidRules) {
if (DEBUG) {
- Slog.v(TAG, "Uid rules changed for " + uid);
+ Slog.v(TAG, "onUidRulesChanged: " + uid);
}
- updateTrackedJobs(uid);
- }
-
- @Override
- public void onRestrictBackgroundChanged(boolean restrictBackground) {
- if (DEBUG) {
- Slog.v(TAG, "Background restriction change to " + restrictBackground);
- }
- updateTrackedJobs(-1);
- }
-
- @Override
- public void onUidPoliciesChanged(int uid, int uidPolicies) {
- if (DEBUG) {
- Slog.v(TAG, "Uid policy changed for " + uid);
- }
- updateTrackedJobs(uid);
+ updateTrackedJobs(uid, null);
}
};
@@ -319,9 +333,6 @@
@Override
public void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate) {
- pw.println("System connected: " + mConnected);
- pw.println();
-
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.valueAt(i);
if (predicate.test(js)) {
@@ -343,8 +354,6 @@
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.CONNECTIVITY);
- proto.write(StateControllerProto.ConnectivityController.IS_CONNECTED, mConnected);
-
for (int i = 0; i < mTrackedJobs.size(); i++) {
final JobStatus js = mTrackedJobs.valueAt(i);
if (!predicate.test(js)) {
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 495109d..c2be283 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -41,7 +41,7 @@
StateController(JobSchedulerService service) {
mService = service;
mStateChangedListener = service;
- mContext = service.getContext();
+ mContext = service.getTestableContext();
mLock = service.getLock();
mConstants = service.getConstants();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 224d085..1782ae5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -70,6 +70,12 @@
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED;
+import static android.provider.Settings.Global.NETPOLICY_QUOTA_ENABLED;
+import static android.provider.Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS;
+import static android.provider.Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH;
+import static android.provider.Settings.Global.NETPOLICY_QUOTA_LIMITED;
+import static android.provider.Settings.Global.NETPOLICY_QUOTA_UNLIMITED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -115,6 +121,7 @@
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -351,6 +358,11 @@
*/
private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
+ private static final long QUOTA_UNLIMITED_DEFAULT = DataUnit.MEBIBYTES.toBytes(20);
+ private static final float QUOTA_LIMITED_DEFAULT = 0.1f;
+ private static final float QUOTA_FRAC_JOBS_DEFAULT = 0.5f;
+ private static final float QUOTA_FRAC_MULTIPATH_DEFAULT = 0.5f;
+
private static final int MSG_RULES_CHANGED = 1;
private static final int MSG_METERED_IFACES_CHANGED = 2;
private static final int MSG_LIMIT_REACHED = 5;
@@ -1739,10 +1751,18 @@
}
mMeteredIfaces = newMeteredIfaces;
+ final ContentResolver cr = mContext.getContentResolver();
+ final boolean quotaEnabled = Settings.Global.getInt(cr,
+ NETPOLICY_QUOTA_ENABLED, 1) != 0;
+ final long quotaUnlimited = Settings.Global.getLong(cr,
+ NETPOLICY_QUOTA_UNLIMITED, QUOTA_UNLIMITED_DEFAULT);
+ final float quotaLimited = Settings.Global.getFloat(cr,
+ NETPOLICY_QUOTA_LIMITED, QUOTA_LIMITED_DEFAULT);
+
// Finally, calculate our opportunistic quotas
- // TODO: add experiments support to disable or tweak ratios
mSubscriptionOpportunisticQuota.clear();
for (NetworkState state : states) {
+ if (!quotaEnabled) continue;
if (state.network == null) continue;
final int subId = getSubIdLocked(state.network);
final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
@@ -1754,7 +1774,7 @@
quotaBytes = OPPORTUNISTIC_QUOTA_UNKNOWN;
} else if (limitBytes == SubscriptionPlan.BYTES_UNLIMITED) {
// Unlimited data; let's use 20MiB/day (600MiB/month)
- quotaBytes = DataUnit.MEBIBYTES.toBytes(20);
+ quotaBytes = quotaUnlimited;
} else {
// Limited data; let's only use 10% of remaining budget
final Pair<ZonedDateTime, ZonedDateTime> cycle = plan.cycleIterator().next();
@@ -1772,7 +1792,7 @@
final long remainingDays =
1 + ((end - now.toEpochMilli() - 1) / TimeUnit.DAYS.toMillis(1));
- quotaBytes = Math.max(0, (remainingBytes / remainingDays) / 10);
+ quotaBytes = Math.max(0, (long) ((remainingBytes / remainingDays) * quotaLimited));
}
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
@@ -3048,11 +3068,17 @@
}
}
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
- overrideMask, overrideValue, subId));
- if (timeoutMillis > 0) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
- overrideMask, 0, subId), timeoutMillis);
+ // Only allow overrides when feature is enabled. However, we always
+ // allow disabling of overrides for safety reasons.
+ final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ NETPOLICY_OVERRIDE_ENABLED, 1) != 0;
+ if (overrideEnabled || overrideValue == 0) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
+ overrideMask, overrideValue, subId));
+ if (timeoutMillis > 0) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
+ overrideMask, 0, subId), timeoutMillis);
+ }
}
}
@@ -4695,11 +4721,24 @@
@Override
public long getSubscriptionOpportunisticQuota(Network network, int quotaType) {
+ final long quotaBytes;
synchronized (mNetworkPoliciesSecondLock) {
- // TODO: handle splitting quota between use-cases
- return mSubscriptionOpportunisticQuota.get(getSubIdLocked(network),
+ quotaBytes = mSubscriptionOpportunisticQuota.get(getSubIdLocked(network),
OPPORTUNISTIC_QUOTA_UNKNOWN);
}
+ if (quotaBytes == OPPORTUNISTIC_QUOTA_UNKNOWN) {
+ return OPPORTUNISTIC_QUOTA_UNKNOWN;
+ }
+
+ if (quotaType == QUOTA_TYPE_JOBS) {
+ return (long) (quotaBytes * Settings.Global.getFloat(mContext.getContentResolver(),
+ NETPOLICY_QUOTA_FRAC_JOBS, QUOTA_FRAC_JOBS_DEFAULT));
+ } else if (quotaType == QUOTA_TYPE_MULTIPATH) {
+ return (long) (quotaBytes * Settings.Global.getFloat(mContext.getContentResolver(),
+ NETPOLICY_QUOTA_FRAC_MULTIPATH, QUOTA_FRAC_MULTIPATH_DEFAULT));
+ } else {
+ return OPPORTUNISTIC_QUOTA_UNKNOWN;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index cf7dfd0..79f80e6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -618,6 +618,7 @@
boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
int mVeryLongPressTimeout;
+ boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
private boolean mHandleVolumeKeysInWM;
@@ -1622,7 +1623,11 @@
: mKeyguardDelegate.isShowing();
if (!keyguardActive) {
Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
- startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ if (mAllowStartActivityForLongPressOnPowerDuringSetup) {
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ } else {
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ }
}
break;
}
@@ -2134,6 +2139,8 @@
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
mVeryLongPressTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_veryLongPressTimeout);
+ mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
@@ -8661,6 +8668,9 @@
pw.print("mShortPressOnWindowBehavior=");
pw.println(shortPressOnWindowBehaviorToString(mShortPressOnWindowBehavior));
pw.print(prefix);
+ pw.print("mAllowStartActivityForLongPressOnPowerDuringSetup=");
+ pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup);
+ pw.print(prefix);
pw.print("mHasSoftInput="); pw.print(mHasSoftInput);
pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed);
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
index 416469b..9c00d1a 100644
--- a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
+++ b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
@@ -37,6 +37,8 @@
private ArrayList<Runnable> mTmpRunnableList = new ArrayList<>();
+ private boolean mEndingDeferredFinish;
+
/**
* Notifies that an {@link AppWindowToken} has started animating.
*/
@@ -50,6 +52,11 @@
void notifyFinished(AppWindowToken token) {
mAnimatingTokens.remove(token);
mFinishedTokens.remove(token);
+
+ // If we were the last token, make sure the end all deferred finishes.
+ if (mAnimatingTokens.isEmpty()) {
+ endDeferringFinished();
+ }
}
/**
@@ -78,16 +85,28 @@
}
private void endDeferringFinished() {
- // Copy it into a separate temp list to avoid modifying the collection while iterating as
- // calling the callback may call back into notifyFinished.
- for (int i = mFinishedTokens.size() - 1; i >= 0; i--) {
- mTmpRunnableList.add(mFinishedTokens.valueAt(i));
+
+ // Don't start recursing. Running the finished listener invokes notifyFinished, which may
+ // invoked us again.
+ if (mEndingDeferredFinish) {
+ return;
}
- mFinishedTokens.clear();
- for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) {
- mTmpRunnableList.get(i).run();
+ try {
+ mEndingDeferredFinish = true;
+
+ // Copy it into a separate temp list to avoid modifying the collection while iterating
+ // as calling the callback may call back into notifyFinished.
+ for (int i = mFinishedTokens.size() - 1; i >= 0; i--) {
+ mTmpRunnableList.add(mFinishedTokens.valueAt(i));
+ }
+ mFinishedTokens.clear();
+ for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) {
+ mTmpRunnableList.get(i).run();
+ }
+ mTmpRunnableList.clear();
+ } finally {
+ mEndingDeferredFinish = false;
}
- mTmpRunnableList.clear();
}
void dump(PrintWriter pw, String header, String prefix) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 8fa94fb..9a4db65 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1714,7 +1714,8 @@
adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
mService.mAppTransition.canSkipFirstFrame(),
- mService.mAppTransition.getAppStackClipMode()),
+ mService.mAppTransition.getAppStackClipMode(),
+ true /* isAppAnimation */),
mService.mSurfaceAnimationRunner);
if (a.getZAdjustment() == Animation.ZORDER_TOP) {
mNeedsZBoost = true;
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 529aacc..d89d6f0 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -146,6 +146,13 @@
return false;
}
+ /**
+ * @return {@code true} if we need to wake-up SurfaceFlinger earlier during this animation.
+ *
+ * @see Transaction#setEarlyWakeup
+ */
+ default boolean needsEarlyWakeup() { return false; }
+
void dump(PrintWriter pw, String prefix);
default void writeToProto(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e8f4545..318b3d2 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -51,6 +51,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Sets;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -290,8 +291,10 @@
mService.mWindowPlacerLocked.performSurfacePlacement();
}
- private void addAnimation(Task task, boolean isRecentTaskInvisible) {
+ @VisibleForTesting
+ AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
+ // TODO: Refactor this to use the task's animator
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
mService);
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
@@ -299,6 +302,15 @@
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
+ return taskAdapter;
+ }
+
+ @VisibleForTesting
+ void removeAnimation(TaskAnimationAdapter taskAdapter) {
+ if (DEBUG) Log.d(TAG, "removeAnimation(" + taskAdapter.mTask.getName() + ")");
+ taskAdapter.mTask.setCanAffectSystemUiFlags(true);
+ taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
+ mPendingAnimations.remove(taskAdapter);
}
void startAnimation() {
@@ -311,12 +323,21 @@
try {
final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- final RemoteAnimationTarget target =
- mPendingAnimations.get(i).createRemoteAnimationApp();
+ final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
+ final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationApp();
if (target != null) {
appAnimations.add(target);
+ } else {
+ removeAnimation(taskAdapter);
}
}
+
+ // Skip the animation if there is nothing to animate
+ if (appAnimations.isEmpty()) {
+ cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+ return;
+ }
+
final RemoteAnimationTarget[] appTargets = appAnimations.toArray(
new RemoteAnimationTarget[appAnimations.size()]);
mPendingStart = false;
@@ -365,14 +386,12 @@
if (DEBUG) Log.d(TAG, "cleanupAnimation(): mPendingAnimations="
+ mPendingAnimations.size());
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
- final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
- adapter.mTask.setCanAffectSystemUiFlags(true);
+ final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
- adapter.mTask.dontAnimateDimExit();
+ taskAdapter.mTask.dontAnimateDimExit();
}
- adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
+ removeAnimation(taskAdapter);
}
- mPendingAnimations.clear();
mRunner.asBinder().unlinkToDeath(this, 0);
// Clear associated input consumers
@@ -457,7 +476,8 @@
return false;
}
- private class TaskAnimationAdapter implements AnimationAdapter {
+ @VisibleForTesting
+ class TaskAnimationAdapter implements AnimationAdapter {
private final Task mTask;
private SurfaceControl mCapturedLeash;
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 98fcb0b..7211533 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -220,6 +220,9 @@
}
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
+ if (a.mAnimSpec.needsEarlyWakeup()) {
+ t.setEarlyWakeup();
+ }
a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 7b7cb30..548e23a 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -47,21 +47,24 @@
private final Point mPosition = new Point();
private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
private final boolean mCanSkipFirstFrame;
+ private final boolean mIsAppAnimation;
private final Rect mStackBounds = new Rect();
private int mStackClipMode;
private final Rect mTmpRect = new Rect();
public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame) {
- this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE);
+ this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE,
+ false /* isAppAnimation */);
}
public WindowAnimationSpec(Animation animation, Point position, Rect stackBounds,
- boolean canSkipFirstFrame, int stackClipMode) {
+ boolean canSkipFirstFrame, int stackClipMode, boolean isAppAnimation) {
mAnimation = animation;
if (position != null) {
mPosition.set(position.x, position.y);
}
mCanSkipFirstFrame = canSkipFirstFrame;
+ mIsAppAnimation = isAppAnimation;
mStackClipMode = stackClipMode;
if (stackBounds != null) {
mStackBounds.set(stackBounds);
@@ -135,6 +138,11 @@
}
@Override
+ public boolean needsEarlyWakeup() {
+ return mIsAppAnimation;
+ }
+
+ @Override
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.println(mAnimation);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 756dc3ab..d10f005 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2001,6 +2001,11 @@
// Try starting an animation.
if (mWinAnimator.applyAnimationLocked(transit, false)) {
mAnimatingExit = true;
+
+ // mAnimatingExit affects canAffectSystemUiFlags(). Run layout such that
+ // any change from that is performed immediately.
+ setDisplayLayoutNeeded();
+ mService.requestTraversal();
}
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ec079da..5cebbd8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8482,6 +8482,7 @@
if (!mHasFeature) {
return null;
}
+ enforceManageUsers();
synchronized (getLockObject()) {
List<String> result = null;
// If we have multiple profiles we return the intersection of the
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index a184b22..87249df 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -40,6 +40,7 @@
import android.net.util.NetdService;
import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
+import android.os.ConditionVariable;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
@@ -150,6 +151,28 @@
public void setNeighborDiscoveryOffload(boolean enable) {}
}
+ public static class WaitForProvisioningCallback extends Callback {
+ private final ConditionVariable mCV = new ConditionVariable();
+ private LinkProperties mCallbackLinkProperties;
+
+ public LinkProperties waitForProvisioning() {
+ mCV.block();
+ return mCallbackLinkProperties;
+ }
+
+ @Override
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ mCallbackLinkProperties = newLp;
+ mCV.open();
+ }
+
+ @Override
+ public void onProvisioningFailure(LinkProperties newLp) {
+ mCallbackLinkProperties = null;
+ mCV.open();
+ }
+ }
+
// Use a wrapper class to log in order to ensure complete and detailed
// logging. This method is lighter weight than annotations/reflection
// and has the following benefits:
@@ -281,6 +304,11 @@
return this;
}
+ public Builder withoutMultinetworkPolicyTracker() {
+ mConfig.mUsingMultinetworkPolicyTracker = false;
+ return this;
+ }
+
public Builder withoutIpReachabilityMonitor() {
mConfig.mUsingIpReachabilityMonitor = false;
return this;
@@ -343,6 +371,7 @@
/* package */ boolean mEnableIPv4 = true;
/* package */ boolean mEnableIPv6 = true;
+ /* package */ boolean mUsingMultinetworkPolicyTracker = true;
/* package */ boolean mUsingIpReachabilityMonitor = true;
/* package */ int mRequestedPreDhcpActionMs;
/* package */ InitialConfiguration mInitialConfig;
@@ -374,6 +403,7 @@
return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
.add("mEnableIPv4: " + mEnableIPv4)
.add("mEnableIPv6: " + mEnableIPv6)
+ .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
.add("mInitialConfig: " + mInitialConfig)
@@ -559,7 +589,6 @@
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
- private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final SharedLog mLog;
private final LocalLog mConnectivityPacketLog;
private final MessageHandlingLogger mMsgStateLogger;
@@ -573,6 +602,7 @@
*/
private LinkProperties mLinkProperties;
private ProvisioningConfiguration mConfiguration;
+ private MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private IpReachabilityMonitor mIpReachabilityMonitor;
private DhcpClient mDhcpClient;
private DhcpResults mDhcpResults;
@@ -685,9 +715,6 @@
mLinkProperties = new LinkProperties();
mLinkProperties.setInterfaceName(mInterfaceName);
- mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
- () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
-
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
@@ -719,8 +746,6 @@
} catch (RemoteException e) {
logError("Couldn't register NetlinkTracker: %s", e);
}
-
- mMultinetworkPolicyTracker.start();
}
private void stopStateMachineUpdaters() {
@@ -729,8 +754,6 @@
} catch (RemoteException e) {
logError("Couldn't unregister NetlinkTracker: %s", e);
}
-
- mMultinetworkPolicyTracker.shutdown();
}
@Override
@@ -1028,7 +1051,8 @@
// Note that we can still be disconnected by IpReachabilityMonitor
// if the IPv6 default gateway (but not the IPv6 DNS servers; see
// accompanying code in IpReachabilityMonitor) is unreachable.
- final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
+ final boolean ignoreIPv6ProvisioningLoss = (mMultinetworkPolicyTracker != null)
+ && !mMultinetworkPolicyTracker.getAvoidBadWifi();
// Additionally:
//
@@ -1520,6 +1544,13 @@
return;
}
+ if (mConfiguration.mUsingMultinetworkPolicyTracker) {
+ mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(
+ mContext, getHandler(),
+ () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
+ mMultinetworkPolicyTracker.start();
+ }
+
if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
doImmediateProvisioningFailure(
IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
@@ -1537,6 +1568,11 @@
mIpReachabilityMonitor = null;
}
+ if (mMultinetworkPolicyTracker != null) {
+ mMultinetworkPolicyTracker.shutdown();
+ mMultinetworkPolicyTracker = null;
+ }
+
if (mDhcpClient != null) {
mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
mDhcpClient.doQuit();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 508a43d..2eb36a2 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -114,35 +114,6 @@
public static class Callback extends IpClient.Callback {
}
- public static class WaitForProvisioningCallback extends Callback {
- private LinkProperties mCallbackLinkProperties;
-
- public LinkProperties waitForProvisioning() {
- synchronized (this) {
- try {
- wait();
- } catch (InterruptedException e) {}
- return mCallbackLinkProperties;
- }
- }
-
- @Override
- public void onProvisioningSuccess(LinkProperties newLp) {
- synchronized (this) {
- mCallbackLinkProperties = newLp;
- notify();
- }
- }
-
- @Override
- public void onProvisioningFailure(LinkProperties newLp) {
- synchronized (this) {
- mCallbackLinkProperties = null;
- notify();
- }
- }
- }
-
public IpManager(Context context, String ifName, Callback callback) {
super(context, ifName, callback);
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index d31d550..d908b8e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -37,9 +37,12 @@
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
+import static android.telephony.SubscriptionPlan.BYTES_UNLIMITED;
import static android.telephony.SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED;
import static android.text.format.Time.TIMEZONE_UTC;
+import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS;
+import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
@@ -1484,6 +1487,102 @@
true);
}
+ @Test
+ public void testOpportunisticQuota() throws Exception {
+ final Network net = new Network(TEST_NET_ID);
+ final NetworkPolicyManagerInternal internal = LocalServices
+ .getService(NetworkPolicyManagerInternal.class);
+
+ // Create a place to store fake usage
+ final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<Long>() {
+ @Override
+ public Long answer(InvocationOnMock invocation) throws Throwable {
+ final NetworkStatsHistory.Entry entry = history.getValues(
+ invocation.getArgument(1), invocation.getArgument(2), null);
+ return entry.rxBytes + entry.txBytes;
+ }
+ });
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<NetworkStats>() {
+ @Override
+ public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
+ return stats;
+ }
+ });
+
+ // Get active mobile network in place
+ expectMobileDefaults();
+ mService.updateNetworks();
+
+ // We're 20% through the month (6 days)
+ final long start = parseTime("2015-11-01T00:00Z");
+ final long end = parseTime("2015-11-07T00:00Z");
+ setCurrentTimeMillis(end);
+
+ // Get some data usage in place
+ history.clear();
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
+
+ // No data plan
+ {
+ reset(mTelephonyManager, mNetworkManager, mNotifManager);
+ expectMobileDefaults();
+
+ mService.updateNetworks();
+
+ // No quotas
+ assertEquals(-1, internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
+ assertEquals(-1, internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
+ }
+
+ // Limited data plan
+ {
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2015-11-01T00:00:00.00Z"))
+ .setDataLimit(DataUnit.MEGABYTES.toBytes(1800), LIMIT_BEHAVIOR_DISABLED)
+ .build();
+ mService.setSubscriptionPlans(TEST_SUB_ID, new SubscriptionPlan[] { plan },
+ mServiceContext.getOpPackageName());
+
+ reset(mTelephonyManager, mNetworkManager, mNotifManager);
+ expectMobileDefaults();
+
+ mService.updateNetworks();
+
+ // We have 1440MB and 24 days left, which is 60MB/day; assuming 10%
+ // for quota split equally between two types gives 3MB.
+ assertEquals(DataUnit.MEGABYTES.toBytes(3),
+ internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
+ assertEquals(DataUnit.MEGABYTES.toBytes(3),
+ internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
+ }
+
+ // Unlimited data plan
+ {
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2015-11-01T00:00:00.00Z"))
+ .setDataLimit(BYTES_UNLIMITED, LIMIT_BEHAVIOR_DISABLED)
+ .build();
+ mService.setSubscriptionPlans(TEST_SUB_ID, new SubscriptionPlan[] { plan },
+ mServiceContext.getOpPackageName());
+
+ reset(mTelephonyManager, mNetworkManager, mNotifManager);
+ expectMobileDefaults();
+
+ mService.updateNetworks();
+
+ // 20MB/day, split equally between two types gives 10MB.
+ assertEquals(DataUnit.MEBIBYTES.toBytes(10),
+ internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_JOBS));
+ assertEquals(DataUnit.MEBIBYTES.toBytes(10),
+ internal.getSubscriptionOpportunisticQuota(net, QUOTA_TYPE_MULTIPATH));
+ }
+ }
+
private ApplicationInfo buildApplicationInfo(String label) {
final ApplicationInfo ai = new ApplicationInfo();
ai.nonLocalizedLabel = label;
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index edc6509..1192114 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -327,6 +327,33 @@
}
@Test
+ public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() throws Exception {
+ Configuration config1 = new Configuration();
+ config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+ TaskRecord task1 = createTaskBuilder(".Task1")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .setStack(mStack)
+ .setUserId(TEST_USER_0_ID)
+ .build();
+ task1.onConfigurationChanged(config1);
+ assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED);
+ mRecentTasks.add(task1);
+ mCallbacksRecorder.clear();
+
+ TaskRecord task2 = createTaskBuilder(".Task1")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .setStack(mStack)
+ .setUserId(TEST_USER_1_ID)
+ .build();
+ assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD);
+ mRecentTasks.add(task2);
+ assertTrue(mCallbacksRecorder.added.size() == 1);
+ assertTrue(mCallbacksRecorder.added.contains(task2));
+ assertTrue(mCallbacksRecorder.trimmed.isEmpty());
+ assertTrue(mCallbacksRecorder.removed.isEmpty());
+ }
+
+ @Test
public void testUsersTasks() throws Exception {
mRecentTasks.setOnlyTestVisibleRange();
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 8874894..5b59e60 100644
--- a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -23,19 +23,28 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkPolicyManager;
import android.os.Build;
-import android.os.Handler;
import android.os.SystemClock;
-import android.support.test.runner.AndroidJUnit4;
import android.util.DataUnit;
import com.android.server.LocalServices;
@@ -45,14 +54,26 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
import java.time.Clock;
import java.time.ZoneOffset;
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
public class ConnectivityControllerTest {
+
+ @Mock private Context mContext;
+ @Mock private ConnectivityManager mConnManager;
+ @Mock private NetworkPolicyManager mNetPolicyManager;
+ @Mock private JobSchedulerService mService;
+
private Constants mConstants;
+ private static final int UID_RED = 10001;
+ private static final int UID_BLUE = 10002;
+
@Before
public void setUp() throws Exception {
// Assume all packages are current SDK
@@ -72,6 +93,19 @@
// Assume default constants for now
mConstants = new Constants();
+
+ // Get our mocks ready
+ when(mContext.getSystemServiceName(ConnectivityManager.class))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
+ when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
+ .thenReturn(mConnManager);
+ when(mContext.getSystemServiceName(NetworkPolicyManager.class))
+ .thenReturn(Context.NETWORK_POLICY_SERVICE);
+ when(mContext.getSystemService(Context.NETWORK_POLICY_SERVICE))
+ .thenReturn(mNetPolicyManager);
+ when(mService.getTestableContext()).thenReturn(mContext);
+ when(mService.getLock()).thenReturn(mService);
+ when(mService.getConstants()).thenReturn(mConstants);
}
@Test
@@ -155,6 +189,99 @@
}
}
+ @Test
+ public void testUpdates() throws Exception {
+ final ArgumentCaptor<NetworkCallback> callback = ArgumentCaptor
+ .forClass(NetworkCallback.class);
+ doNothing().when(mConnManager).registerNetworkCallback(any(), callback.capture());
+
+ final ConnectivityController controller = new ConnectivityController(mService);
+
+ final Network meteredNet = new Network(101);
+ final NetworkCapabilities meteredCaps = createCapabilities();
+ final Network unmeteredNet = new Network(202);
+ final NetworkCapabilities unmeteredCaps = createCapabilities()
+ .addCapability(NET_CAPABILITY_NOT_METERED);
+
+ final JobStatus red = createJobStatus(createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED);
+ final JobStatus blue = createJobStatus(createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY), UID_BLUE);
+
+ // Pretend we're offline when job is added
+ {
+ reset(mConnManager);
+ answerNetwork(UID_RED, null, null);
+ answerNetwork(UID_BLUE, null, null);
+
+ controller.maybeStartTrackingJobLocked(red, null);
+ controller.maybeStartTrackingJobLocked(blue, null);
+
+ assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ assertFalse(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ }
+
+ // Metered network
+ {
+ reset(mConnManager);
+ answerNetwork(UID_RED, meteredNet, meteredCaps);
+ answerNetwork(UID_BLUE, meteredNet, meteredCaps);
+
+ callback.getValue().onCapabilitiesChanged(meteredNet, meteredCaps);
+
+ assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ }
+
+ // Unmetered network background
+ {
+ reset(mConnManager);
+ answerNetwork(UID_RED, meteredNet, meteredCaps);
+ answerNetwork(UID_BLUE, meteredNet, meteredCaps);
+
+ callback.getValue().onCapabilitiesChanged(unmeteredNet, unmeteredCaps);
+
+ assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ }
+
+ // Lost metered network
+ {
+ reset(mConnManager);
+ answerNetwork(UID_RED, unmeteredNet, unmeteredCaps);
+ answerNetwork(UID_BLUE, unmeteredNet, unmeteredCaps);
+
+ callback.getValue().onLost(meteredNet);
+
+ assertTrue(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ }
+
+ // Specific UID was blocked
+ {
+ reset(mConnManager);
+ answerNetwork(UID_RED, null, null);
+ answerNetwork(UID_BLUE, unmeteredNet, unmeteredCaps);
+
+ callback.getValue().onCapabilitiesChanged(unmeteredNet, unmeteredCaps);
+
+ assertFalse(red.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ assertTrue(blue.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY));
+ }
+ }
+
+ private void answerNetwork(int uid, Network net, NetworkCapabilities caps) {
+ when(mConnManager.getActiveNetworkForUid(eq(uid))).thenReturn(net);
+ when(mConnManager.getNetworkCapabilities(eq(net))).thenReturn(caps);
+ if (net != null) {
+ final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, null, null);
+ ni.setDetailedState(DetailedState.CONNECTED, null, null);
+ when(mConnManager.getNetworkInfoForUid(eq(net), eq(uid), anyBoolean())).thenReturn(ni);
+ }
+ }
+
private static NetworkCapabilities createCapabilities() {
return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_VALIDATED);
@@ -165,12 +292,22 @@
}
private static JobStatus createJobStatus(JobInfo.Builder job) {
- return createJobStatus(job, 0, Long.MAX_VALUE);
+ return createJobStatus(job, android.os.Process.NOBODY_UID, 0, Long.MAX_VALUE);
}
- private static JobStatus createJobStatus(JobInfo.Builder job, long earliestRunTimeElapsedMillis,
- long latestRunTimeElapsedMillis) {
- return new JobStatus(job.build(), 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
- latestRunTimeElapsedMillis, 0, 0, null, 0);
+ private static JobStatus createJobStatus(JobInfo.Builder job, int uid) {
+ return createJobStatus(job, uid, 0, Long.MAX_VALUE);
+ }
+
+ private static JobStatus createJobStatus(JobInfo.Builder job,
+ long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+ return createJobStatus(job, android.os.Process.NOBODY_UID,
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
+ }
+
+ private static JobStatus createJobStatus(JobInfo.Builder job, int uid,
+ long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+ return new JobStatus(job.build(), uid, null, -1, 0, 0, null,
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 8b78f10..164c80b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -88,4 +88,25 @@
verify(mMockEndDeferFinishCallback1).run();
verifyZeroInteractions(mMockEndDeferFinishCallback2);
}
+
+ @Test
+ public void testContainerRemoved() throws Exception {
+ final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
+ "window2").mAppToken;
+ final AnimatingAppWindowTokenRegistry registry =
+ window1.getStack().getAnimatingAppWindowTokenRegistry();
+
+ window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
+ window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
+ assertTrue(window1.isSelfAnimating());
+ assertTrue(window2.isSelfAnimating());
+
+ // Make sure that first animation finish is deferred, and removing the second window stops
+ // finishes all pending deferred finishings.
+ registry.notifyAboutToFinish(window1, mMockEndDeferFinishCallback1);
+ window2.setParent(null);
+ verify(mMockEndDeferFinishCallback1).run();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 7f1bcac..845095a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -46,6 +46,7 @@
import android.graphics.Rect;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.DisplayMetrics;
@@ -56,7 +57,9 @@
import com.android.server.wm.utils.WmDisplayCutout;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -72,6 +75,7 @@
public class DisplayContentTests extends WindowTestsBase {
@Test
+ @FlakyTest(bugId = 77772044)
public void testForAllWindows() throws Exception {
final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
mDisplayContent, "exiting app");
@@ -495,24 +499,24 @@
assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
}
- private void assertForAllWindowsOrder(List<WindowState> expectedWindows) {
- final LinkedList<WindowState> actualWindows = new LinkedList();
+ private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
+ final LinkedList<WindowState> actualWindows = new LinkedList<>();
// Test forward traversal.
mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
- assertEquals(expectedWindows.size(), actualWindows.size());
- for (WindowState w : expectedWindows) {
- assertEquals(w, actualWindows.pollFirst());
- }
- assertTrue(actualWindows.isEmpty());
+ assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
+
+ actualWindows.clear();
// Test backward traversal.
mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
- assertEquals(expectedWindows.size(), actualWindows.size());
- for (WindowState w : expectedWindows) {
- assertEquals(w, actualWindows.pollLast());
- }
- assertTrue(actualWindows.isEmpty());
+ assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
+ }
+
+ private static List<WindowState> reverseList(List<WindowState> list) {
+ final ArrayList<WindowState> result = new ArrayList<>(list);
+ Collections.reverse(result);
+ return result;
}
private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
new file mode 100644
index 0000000..fbf6691
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Binder;
+import android.os.IInterface;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.IRecentsAnimationRunner;
+import android.view.SurfaceControl;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest FrameworksServicesTests:com.android.server.wm.RecentsAnimationControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class RecentsAnimationControllerTest extends WindowTestsBase {
+
+ @Mock SurfaceControl mMockLeash;
+ @Mock SurfaceControl.Transaction mMockTransaction;
+ @Mock OnAnimationFinishedCallback mFinishedCallback;
+ @Mock IRecentsAnimationRunner mMockRunner;
+ @Mock RecentsAnimationController.RecentsAnimationCallbacks mAnimationCallbacks;
+ private RecentsAnimationController mController;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ when(mMockRunner.asBinder()).thenReturn(new Binder());
+ mController = new RecentsAnimationController(sWm, mMockRunner, mAnimationCallbacks,
+ DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testRemovedBeforeStarted_expectCanceled() throws Exception {
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(),
+ false /* isRecentTaskInvisible */);
+ adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+
+ // Remove the app window so that the animation target can not be created
+ appWindow.removeImmediately();
+ mController.startAnimation();
+
+ // Verify that the finish callback to reparent the leash is called
+ verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ // Verify the animation canceled callback to the app was made
+ verify(mMockRunner).onAnimationCanceled();
+ verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
+ }
+
+ private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
+ verify(binder, atLeast(0)).asBinder();
+ verifyNoMoreInteractions(binder);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java
index 794d033..ca520ed 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -56,7 +56,8 @@
Rect windowCrop = new Rect(0, 0, 20, 20);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
- mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE);
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(windowCrop)));
@@ -65,7 +66,8 @@
@Test
public void testApply_clipAfter() {
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
- mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM);
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
@@ -77,7 +79,8 @@
// Stack bounds is (0, 0, 10, 10) position is (20, 40)
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation,
new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */,
- STACK_CLIP_AFTER_ANIM);
+ STACK_CLIP_AFTER_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
@@ -89,7 +92,8 @@
public void testApply_clipBeforeNoAnimationBounds() {
// Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 0, 0)
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
- mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(mStackBounds)));
@@ -102,7 +106,8 @@
Animation a = createClipRectAnimation(windowCrop, windowCrop);
a.initialize(0, 0, 0, 0);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
- null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
}
@@ -113,7 +118,8 @@
Rect windowCrop = new Rect(0, 0, 5, 5);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
- mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(windowCrop)));
@@ -125,7 +131,8 @@
Rect windowCrop = new Rect(0, 0, 20, 20);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
- mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+ mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+ true /* isAppAnimation */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(mStackBounds)));
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index fef702e..9364ec8 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -34,7 +34,7 @@
import android.net.apf.ApfFilter.ApfConfiguration;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.net.util.InterfaceParams;
@@ -606,7 +606,7 @@
}
}
- private class MockIpManagerCallback extends IpManager.Callback {
+ private class MockIpClientCallback extends IpClient.Callback {
private final ConditionVariable mGotApfProgram = new ConditionVariable();
private byte[] mLastApfProgram;
@@ -637,8 +637,8 @@
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
public TestApfFilter(Context context, ApfConfiguration config,
- IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception {
- super(context, config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
+ IpClient.Callback ipClientCallback, IpConnectivityLog log) throws Exception {
+ super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -761,29 +761,29 @@
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
// Helper to initialize a default apfFilter.
- private ApfFilter setupApfFilter(IpManager.Callback ipManagerCallback, ApfConfiguration config)
+ private ApfFilter setupApfFilter(IpClient.Callback ipClientCallback, ApfConfiguration config)
throws Exception {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
apfFilter.setLinkProperties(lp);
return apfFilter;
}
@Test
public void testApfFilterIPv4() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
apfFilter.setLinkProperties(lp);
- byte[] program = ipManagerCallback.getApfProgram();
+ byte[] program = ipClientCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
@@ -830,10 +830,10 @@
@Test
public void testApfFilterIPv6() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
- byte[] program = ipManagerCallback.getApfProgram();
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+ byte[] program = ipClientCallback.getApfProgram();
// Verify empty IPv6 packet is passed
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
@@ -868,17 +868,17 @@
final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
ApfConfiguration config = getDefaultConfig();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
apfFilter.setLinkProperties(lp);
- byte[] program = ipManagerCallback.getApfProgram();
+ byte[] program = ipClientCallback.getApfProgram();
// Construct IPv4 and IPv6 multicast packets.
ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
@@ -915,9 +915,9 @@
assertPass(program, bcastv4unicastl2packet.array());
// Turn on multicast filter and verify it works
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.setMulticastFilter(true);
- program = ipManagerCallback.getApfProgram();
+ program = ipClientCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
assertDrop(program, mcastv6packet.array());
assertDrop(program, bcastv4packet1.array());
@@ -925,9 +925,9 @@
assertDrop(program, bcastv4unicastl2packet.array());
// Turn off multicast filter and verify it's off
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.setMulticastFilter(false);
- program = ipManagerCallback.getApfProgram();
+ program = ipClientCallback.getApfProgram();
assertPass(program, mcastv4packet.array());
assertPass(program, mcastv6packet.array());
assertPass(program, bcastv4packet1.array());
@@ -935,13 +935,13 @@
assertPass(program, bcastv4unicastl2packet.array());
// Verify it can be initialized to on
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.shutdown();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
apfFilter.setLinkProperties(lp);
- program = ipManagerCallback.getApfProgram();
+ program = ipClientCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
assertDrop(program, mcastv6packet.array());
assertDrop(program, bcastv4packet1.array());
@@ -956,8 +956,8 @@
@Test
public void testApfFilterMulticastPingWhileDozing() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = setupApfFilter(ipManagerCallback, getDefaultConfig());
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+ ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
// Construct a multicast ICMPv6 ECHO request.
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
@@ -968,35 +968,35 @@
put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
// Normally, we let multicast pings alone...
- assertPass(ipManagerCallback.getApfProgram(), packet.array());
+ assertPass(ipClientCallback.getApfProgram(), packet.array());
// ...and even while dozing...
apfFilter.setDozeMode(true);
- assertPass(ipManagerCallback.getApfProgram(), packet.array());
+ assertPass(ipClientCallback.getApfProgram(), packet.array());
// ...but when the multicast filter is also enabled, drop the multicast pings to save power.
apfFilter.setMulticastFilter(true);
- assertDrop(ipManagerCallback.getApfProgram(), packet.array());
+ assertDrop(ipClientCallback.getApfProgram(), packet.array());
// However, we should still let through all other ICMPv6 types.
ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
- assertPass(ipManagerCallback.getApfProgram(), raPacket.array());
+ assertPass(ipClientCallback.getApfProgram(), raPacket.array());
// Now wake up from doze mode to ensure that we no longer drop the packets.
// (The multicast filter is still enabled at this point).
apfFilter.setDozeMode(false);
- assertPass(ipManagerCallback.getApfProgram(), packet.array());
+ assertPass(ipClientCallback.getApfProgram(), packet.array());
apfFilter.shutdown();
}
@Test
public void testApfFilter802_3() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
- ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
- byte[] program = ipManagerCallback.getApfProgram();
+ ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
+ byte[] program = ipClientCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
// Note that eth-type = 0 makes it an IEEE802.3 frame
@@ -1012,11 +1012,11 @@
assertPass(program, packet.array());
// Now turn on the filter
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = setupApfFilter(ipManagerCallback, config);
- program = ipManagerCallback.getApfProgram();
+ apfFilter = setupApfFilter(ipClientCallback, config);
+ program = ipClientCallback.getApfProgram();
// Verify that IEEE802.3 frame is dropped
// In this case ethtype is used for payload length
@@ -1040,10 +1040,10 @@
final int[] ipv4BlackList = {ETH_P_IP};
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
- ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
- byte[] program = ipManagerCallback.getApfProgram();
+ ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
+ byte[] program = ipClientCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
// Note that eth-type = 0 makes it an IEEE802.3 frame
@@ -1059,11 +1059,11 @@
assertPass(program, packet.array());
// Now add IPv4 to the black list
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4BlackList;
- apfFilter = setupApfFilter(ipManagerCallback, config);
- program = ipManagerCallback.getApfProgram();
+ apfFilter = setupApfFilter(ipClientCallback, config);
+ program = ipClientCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
@@ -1074,11 +1074,11 @@
assertPass(program, packet.array());
// Now let us have both IPv4 and IPv6 in the black list
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4Ipv6BlackList;
- apfFilter = setupApfFilter(ipManagerCallback, config);
- program = ipManagerCallback.getApfProgram();
+ apfFilter = setupApfFilter(ipClientCallback, config);
+ program = ipClientCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
@@ -1091,7 +1091,7 @@
apfFilter.shutdown();
}
- private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) {
+ private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
cb.resetApfProgramWait();
filter.setLinkProperties(lp);
return cb.getApfProgram();
@@ -1114,23 +1114,23 @@
@Test
public void testApfFilterArp() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
- verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
+ verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
// Inform ApfFilter of our address and verify ARP filtering is on
LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
LinkProperties lp = new LinkProperties();
assertTrue(lp.addLinkAddress(linkAddress));
- verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
+ verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
// Inform ApfFilter of loss of IP and verify ARP filtering is off
- verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
+ verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
apfFilter.shutdown();
}
@@ -1161,7 +1161,7 @@
return packet.array();
}
- // Verify that the last program pushed to the IpManager.Callback properly filters the
+ // Verify that the last program pushed to the IpClient.Callback properly filters the
// given packet for the given lifetime.
private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
final int FRACTION_OF_LIFETIME = 6;
@@ -1191,12 +1191,12 @@
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
// for the given lifetime.
- private void verifyRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
+ private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
// Verify new program generated if ApfFilter witnesses RA
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.pretendPacketReceived(packet.array());
- byte[] program = ipManagerCallback.getApfProgram();
+ byte[] program = ipClientCallback.getApfProgram();
verifyRaLifetime(program, packet, lifetime);
}
@@ -1229,21 +1229,21 @@
&& (ev1.dnsslLifetime == ev2.dnsslLifetime);
}
- private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
+ private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
ByteBuffer packet) throws IOException, ErrnoException {
- ipManagerCallback.resetApfProgramWait();
+ ipClientCallback.resetApfProgramWait();
apfFilter.pretendPacketReceived(packet.array());
- ipManagerCallback.assertNoProgramUpdate();
+ ipClientCallback.assertNoProgramUpdate();
}
@Test
public void testApfFilterRa() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
- byte[] program = ipManagerCallback.getApfProgram();
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+ byte[] program = ipClientCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
final int PREFIX_VALID_LIFETIME = 200;
@@ -1268,7 +1268,7 @@
basePacket.put(IPV6_ALL_NODES_ADDRESS);
assertPass(program, basePacket.array());
- verifyRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
+ verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
@@ -1286,7 +1286,7 @@
zeroLengthOptionPacket.put(basePacket);
zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
zeroLengthOptionPacket.put((byte)0);
- assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket);
+ assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
// Generate several RAs with different options and lifetimes, and verify when
// ApfFilter is shown these packets, it generates programs to filter them for the
@@ -1304,7 +1304,7 @@
ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
PREFIX_VALID_LIFETIME);
verifyRaLifetime(
- apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+ apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
verifyRaEvent(new RaEvent(
ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
@@ -1316,7 +1316,7 @@
rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
rdnssOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
- verifyRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
@@ -1327,7 +1327,7 @@
routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
routeInfoOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
- verifyRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
+ verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
@@ -1338,11 +1338,11 @@
dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
dnsslOptionPacket.putInt(
ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
- verifyRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
+ verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
// Verify that current program filters all five RAs:
- program = ipManagerCallback.getApfProgram();
+ program = ipClientCallback.getApfProgram();
verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
@@ -1384,7 +1384,7 @@
public void testRaParsing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- MockIpManagerCallback cb = new MockIpManagerCallback();
+ MockIpClientCallback cb = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
@@ -1405,7 +1405,7 @@
public void testRaProcessing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- MockIpManagerCallback cb = new MockIpManagerCallback();
+ MockIpClientCallback cb = new MockIpClientCallback();
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 2ff92e6..e6d94e6 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -111,6 +111,7 @@
"link/XmlReferenceLinker.cpp",
"optimize/MultiApkGenerator.cpp",
"optimize/ResourceDeduper.cpp",
+ "optimize/ResourceFilter.cpp",
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
"split/TableSplitter.cpp",
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 5dff8d8..54509d9 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <cinttypes>
+#include <algorithm>
#include <queue>
#include <unordered_map>
#include <vector>
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index da32010..4afa8f0 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -38,6 +38,7 @@
#include "io/Util.h"
#include "optimize/MultiApkGenerator.h"
#include "optimize/ResourceDeduper.h"
+#include "optimize/ResourceFilter.h"
#include "optimize/VersionCollapser.h"
#include "split/TableSplitter.h"
#include "util/Files.h"
@@ -62,6 +63,9 @@
// Details of the app extracted from the AndroidManifest.xml
AppInfo app_info;
+ // Blacklist of unused resources that should be removed from the apk.
+ std::unordered_set<ResourceName> resources_blacklist;
+
// Split APK options.
TableSplitterOptions table_splitter_options;
@@ -151,6 +155,13 @@
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK...");
}
+ if (!options_.resources_blacklist.empty()) {
+ ResourceFilter filter(options_.resources_blacklist);
+ if (!filter.Consume(context_, apk->GetResourceTable())) {
+ context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources");
+ return 1;
+ }
+ }
VersionCollapser collapser;
if (!collapser.Consume(context_, apk->GetResourceTable())) {
@@ -288,16 +299,62 @@
OptimizeContext* context_;
};
-bool ExtractWhitelistFromConfig(const std::string& path, OptimizeContext* context,
- OptimizeOptions* options) {
+bool ExtractObfuscationWhitelistFromConfig(const std::string& path, OptimizeContext* context,
+ OptimizeOptions* options) {
std::string contents;
if (!ReadFileToString(path, &contents, true)) {
context->GetDiagnostics()->Error(DiagMessage()
<< "failed to parse whitelist from config file: " << path);
return false;
}
- for (const StringPiece& resource_name : util::Tokenize(contents, ',')) {
- options->table_flattener_options.whitelisted_resources.insert(resource_name.to_string());
+ for (StringPiece resource_name : util::Tokenize(contents, ',')) {
+ options->table_flattener_options.whitelisted_resources.insert(
+ resource_name.to_string());
+ }
+ return true;
+}
+
+bool ExtractConfig(const std::string& path, OptimizeContext* context,
+ OptimizeOptions* options) {
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
+ context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading whitelist");
+ return false;
+ }
+
+ size_t line_no = 0;
+ for (StringPiece line : util::Tokenize(content, '\n')) {
+ line_no++;
+ line = util::TrimWhitespace(line);
+ if (line.empty()) {
+ continue;
+ }
+
+ auto split_line = util::Split(line, '#');
+ if (split_line.size() < 2) {
+ context->GetDiagnostics()->Error(DiagMessage(line) << "No # found in line");
+ return false;
+ }
+ StringPiece resource_string = split_line[0];
+ StringPiece directives = split_line[1];
+ ResourceNameRef resource_name;
+ if (!ResourceUtils::ParseResourceName(resource_string, &resource_name)) {
+ context->GetDiagnostics()->Error(DiagMessage(line) << "Malformed resource name");
+ return false;
+ }
+ if (!resource_name.package.empty()) {
+ context->GetDiagnostics()->Error(DiagMessage(line)
+ << "Package set for resource. Only use type/name");
+ return false;
+ }
+ for (StringPiece directive : util::Tokenize(directives, ',')) {
+ if (directive == "remove") {
+ options->resources_blacklist.insert(resource_name.ToResourceName());
+ } else if (directive == "no_obfuscate") {
+ options->table_flattener_options.whitelisted_resources.insert(
+ resource_name.entry.to_string());
+ }
+ }
}
return true;
}
@@ -326,6 +383,7 @@
OptimizeOptions options;
Maybe<std::string> config_path;
Maybe<std::string> whitelist_path;
+ Maybe<std::string> resources_config_path;
Maybe<std::string> target_densities;
std::vector<std::string> configs;
std::vector<std::string> split_args;
@@ -344,10 +402,15 @@
"All the resources that would be unused on devices of the given densities will be \n"
"removed from the APK.",
&target_densities)
- .OptionalFlag("--whitelist-config-path",
+ .OptionalFlag("--whitelist-path",
"Path to the whitelist.cfg file containing whitelisted resources \n"
"whose names should not be altered in final resource tables.",
&whitelist_path)
+ .OptionalFlag("--resources-config-path",
+ "Path to the resources.cfg file containing the list of resources and \n"
+ "directives to each resource. \n"
+ "Format: type/resource_name#[directive][,directive]",
+ &resources_config_path)
.OptionalFlagList("-c",
"Comma separated list of configurations to include. The default\n"
"is all configurations.",
@@ -464,12 +527,19 @@
if (options.table_flattener_options.collapse_key_stringpool) {
if (whitelist_path) {
std::string& path = whitelist_path.value();
- if (!ExtractWhitelistFromConfig(path, &context, &options)) {
+ if (!ExtractObfuscationWhitelistFromConfig(path, &context, &options)) {
return 1;
}
}
}
+ if (resources_config_path) {
+ std::string& path = resources_config_path.value();
+ if (!ExtractConfig(path, &context, &options)) {
+ return 1;
+ }
+ }
+
if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) {
return 1;
}
diff --git a/tools/aapt2/optimize/ResourceFilter.cpp b/tools/aapt2/optimize/ResourceFilter.cpp
new file mode 100644
index 0000000..250b651
--- /dev/null
+++ b/tools/aapt2/optimize/ResourceFilter.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "optimize/ResourceFilter.h"
+
+#include "ResourceTable.h"
+
+namespace aapt {
+
+ResourceFilter::ResourceFilter(const std::unordered_set<ResourceName>& blacklist)
+ : blacklist_(blacklist) {
+}
+
+bool ResourceFilter::Consume(IAaptContext* context, ResourceTable* table) {
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto it = type->entries.begin(); it != type->entries.end(); ) {
+ ResourceName resource = ResourceName({}, type->type, (*it)->name);
+ if (blacklist_.find(resource) != blacklist_.end()) {
+ it = type->entries.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourceFilter.h b/tools/aapt2/optimize/ResourceFilter.h
new file mode 100644
index 0000000..d4baf65
--- /dev/null
+++ b/tools/aapt2/optimize/ResourceFilter.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_OPTIMIZE_RESOURCEFILTER_H
+#define AAPT_OPTIMIZE_RESOURCEFILTER_H
+
+#include "android-base/macros.h"
+
+#include "process/IResourceTableConsumer.h"
+
+#include <unordered_set>
+
+namespace aapt {
+
+// Removes non-whitelisted entries from resource table.
+class ResourceFilter : public IResourceTableConsumer {
+ public:
+ explicit ResourceFilter(const std::unordered_set<ResourceName>& blacklist);
+
+ bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceFilter);
+ std::unordered_set<ResourceName> blacklist_;
+};
+
+} // namespace aapt
+
+#endif // AAPT_OPTIMIZE_RESOURCEFILTER_H
diff --git a/tools/aapt2/optimize/ResourceFilter_test.cpp b/tools/aapt2/optimize/ResourceFilter_test.cpp
new file mode 100644
index 0000000..800b2bf
--- /dev/null
+++ b/tools/aapt2/optimize/ResourceFilter_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "optimize/ResourceFilter.h"
+
+#include "ResourceTable.h"
+#include "test/Test.h"
+
+using ::aapt::test::HasValue;
+using ::testing::Not;
+
+namespace aapt {
+
+TEST(ResourceFilterTest, SomeValuesAreFilteredOut) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ const ConfigDescription default_config = {};
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:string/notblacklisted2", ResourceId{}, default_config, "value")
+ .AddString("android:string/blacklisted2", ResourceId{}, default_config, "value")
+ .Build();
+
+ std::unordered_set<ResourceName> blacklist = {
+ ResourceName({}, ResourceType::kString, "blacklisted"),
+ ResourceName({}, ResourceType::kString, "blacklisted2"),
+ };
+
+ ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
+ EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
+ EXPECT_THAT(table, HasValue("android:string/notblacklisted2", default_config));
+ EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
+ EXPECT_THAT(table, Not(HasValue("android:string/blacklisted2", default_config)));
+}
+
+TEST(ResourceFilterTest, TypeIsCheckedBeforeFiltering) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ const ConfigDescription default_config = {};
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:drawable/notblacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:drawable/blacklisted", ResourceId{}, default_config, "value")
+ .Build();
+
+ std::unordered_set<ResourceName> blacklist = {
+ ResourceName({}, ResourceType::kString, "blacklisted"),
+ };
+
+ ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
+ EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
+ EXPECT_THAT(table, HasValue("android:drawable/blacklisted", default_config));
+ EXPECT_THAT(table, HasValue("android:drawable/notblacklisted", default_config));
+ EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
+}
+
+} // namespace aapt
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 1a79a76..f6c67c9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -613,37 +613,6 @@
/**
* @hide
- * Last time the system tried to connect and failed.
- */
- public long lastConnectionFailure;
-
- /**
- * @hide
- * Last time the system tried to roam and failed because of authentication failure or DHCP
- * RENEW failure.
- */
- public long lastRoamingFailure;
-
- /** @hide */
- public static int ROAMING_FAILURE_IP_CONFIG = 1;
- /** @hide */
- public static int ROAMING_FAILURE_AUTH_FAILURE = 2;
-
- /**
- * @hide
- * Initial amount of time this Wifi configuration gets blacklisted for network switching
- * because of roaming failure
- */
- public long roamingFailureBlackListTimeMilli = 1000;
-
- /**
- * @hide
- * Last roaming failure reason code
- */
- public int lastRoamingFailureReason;
-
- /**
- * @hide
* Last time the system was disconnected to this configuration.
*/
public long lastDisconnected;
@@ -1752,28 +1721,6 @@
sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
sbuf.append(" ");
}
- if (this.lastConnectionFailure != 0) {
- sbuf.append('\n');
- long diff = now_ms - this.lastConnectionFailure;
- if (diff <= 0) {
- sbuf.append("lastConnectionFailure since <incorrect> ");
- } else {
- sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
- sbuf.append("sec ");
- }
- }
- if (this.lastRoamingFailure != 0) {
- sbuf.append('\n');
- long diff = now_ms - this.lastRoamingFailure;
- if (diff <= 0) {
- sbuf.append("lastRoamingFailure since <incorrect> ");
- } else {
- sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
- sbuf.append("sec ");
- }
- }
- sbuf.append("roamingFailureBlackListTimeMilli: ").
- append(Long.toString(this.roamingFailureBlackListTimeMilli));
sbuf.append('\n');
if (this.linkedConfigurations != null) {
for (String key : this.linkedConfigurations.keySet()) {
@@ -2118,10 +2065,6 @@
lastConnected = source.lastConnected;
lastDisconnected = source.lastDisconnected;
- lastConnectionFailure = source.lastConnectionFailure;
- lastRoamingFailure = source.lastRoamingFailure;
- lastRoamingFailureReason = source.lastRoamingFailureReason;
- roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
numScorerOverride = source.numScorerOverride;
numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
numAssociation = source.numAssociation;
@@ -2187,10 +2130,6 @@
dest.writeInt(lastUpdateUid);
dest.writeString(creatorName);
dest.writeString(lastUpdateName);
- dest.writeLong(lastConnectionFailure);
- dest.writeLong(lastRoamingFailure);
- dest.writeInt(lastRoamingFailureReason);
- dest.writeLong(roamingFailureBlackListTimeMilli);
dest.writeInt(numScorerOverride);
dest.writeInt(numScorerOverrideAndSwitchedNetwork);
dest.writeInt(numAssociation);
@@ -2256,10 +2195,6 @@
config.lastUpdateUid = in.readInt();
config.creatorName = in.readString();
config.lastUpdateName = in.readString();
- config.lastConnectionFailure = in.readLong();
- config.lastRoamingFailure = in.readLong();
- config.lastRoamingFailureReason = in.readInt();
- config.roamingFailureBlackListTimeMilli = in.readLong();
config.numScorerOverride = in.readInt();
config.numScorerOverrideAndSwitchedNetwork = in.readInt();
config.numAssociation = in.readInt();