Merge "Allow Instant Apps access PackageInfo of exposed apps"
diff --git a/api/current.txt b/api/current.txt
index 9557ee5..f21d18f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7122,6 +7122,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -12758,7 +12759,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12782,6 +12783,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13005,6 +13009,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13521,6 +13529,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -37158,11 +37170,11 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CANCEL = 2; // 0x2
+ field public static final int REASON_CANCEL_ALL = 3; // 0x3
field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_CLICK = 1; // 0x1
+ field public static final int REASON_ERROR = 4; // 0x4
field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -45076,8 +45088,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -47593,6 +47605,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6d01c6b..26d43e3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7591,6 +7591,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -13492,7 +13493,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -13516,6 +13517,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13739,6 +13743,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -14255,6 +14263,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -40229,11 +40241,11 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CANCEL = 2; // 0x2
+ field public static final int REASON_CANCEL_ALL = 3; // 0x3
field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_CLICK = 1; // 0x1
+ field public static final int REASON_ERROR = 4; // 0x4
field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -48539,8 +48551,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -51059,6 +51071,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 1d0a289..49bab6f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7149,6 +7149,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -12796,7 +12797,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12820,6 +12821,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13043,6 +13047,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13559,6 +13567,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -37334,11 +37346,11 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+ field public static final int REASON_CANCEL = 2; // 0x2
+ field public static final int REASON_CANCEL_ALL = 3; // 0x3
field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
+ field public static final int REASON_CLICK = 1; // 0x1
+ field public static final int REASON_ERROR = 4; // 0x4
field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
@@ -45436,8 +45448,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -47962,6 +47974,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 78c29e8..e65c7c8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,7 @@
package android.app;
+import android.metrics.LogMaker;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -23,6 +24,8 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.PhoneWindow;
import android.annotation.CallSuper;
@@ -765,6 +768,7 @@
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
static final class NonConfigurationInstances {
Object activity;
@@ -7188,6 +7192,8 @@
public void autofill(List<AutofillId> ids, List<AutofillValue> values) {
final View root = getWindow().getDecorView();
final int itemCount = ids.size();
+ int numApplied = 0;
+
for (int i = 0; i < itemCount; i++) {
final AutofillId id = ids.get(i);
final AutofillValue value = values.get(i);
@@ -7197,12 +7203,22 @@
Log.w(TAG, "autofill(): no View with id " + viewId);
continue;
}
+ final boolean wasApplied;
if (id.isVirtual()) {
- view.autofillVirtual(id.getVirtualChildId(), value);
+ wasApplied = view.autofillVirtual(id.getVirtualChildId(), value);
} else {
- view.autofill(value);
+ wasApplied = view.autofill(value);
+ }
+
+ if (wasApplied) {
+ numApplied++;
}
}
+
+ LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
+ mMetricsLogger.write(log);
}
/** @hide */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9b64f0c..6b53cd8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -337,6 +337,8 @@
Configuration overrideConfig;
// Used for consolidating configs before sending on to Activity.
private Configuration tmpConfig = new Configuration();
+ // Callback used for updating activity override config.
+ ViewRootImpl.ActivityConfigCallback configCallback;
ActivityClientRecord nextIdle;
ProfilerInfo profilerInfo;
@@ -372,6 +374,14 @@
stopped = false;
hideForNow = false;
nextIdle = null;
+ configCallback = (Configuration overrideConfig, int newDisplayId) -> {
+ if (activity == null) {
+ throw new IllegalStateException(
+ "Received config update for non-existing activity");
+ }
+ activity.mMainThread.handleActivityConfigurationChanged(
+ new ActivityConfigChangeData(token, overrideConfig), newDisplayId);
+ };
}
public boolean isPreHoneycomb() {
@@ -3681,6 +3691,12 @@
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
+ final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
+ if (viewRoot != null) {
+ // TODO: Figure out the best place to set the callback.
+ // This looks like a place where decor view is already initialized.
+ viewRoot.setActivityConfigCallback(r.configCallback);
+ }
}
if (!r.onlyLocalRequest) {
@@ -5029,7 +5045,7 @@
* @param displayId Id of the display where activity was moved to, -1 if there was no move and
* value didn't change.
*/
- private void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) {
+ void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) {
ActivityClientRecord r = mActivities.get(data.activityToken);
// Check input params.
if (r == null || r.activity == null) {
@@ -5046,6 +5062,7 @@
// Perform updates.
r.overrideConfig = data.overrideConfig;
+ final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
if (movedToDifferentDisplay) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:"
+ r.activityInfo.name + ", displayId=" + displayId
@@ -5053,13 +5070,15 @@
performConfigurationChangedForActivity(r, mCompatConfiguration, displayId,
true /* movedToDifferentDisplay */);
- final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl();
viewRoot.onMovedToDisplay(displayId);
} else {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
+ r.activityInfo.name + ", config=" + data.overrideConfig);
performConfigurationChangedForActivity(r, mCompatConfiguration);
}
+ // Notify the ViewRootImpl instance about configuration changes. It may have initiated this
+ // update to make sure that resources are updated before updating itself.
+ viewRoot.updateConfiguration();
mSomeActivitiesChanged = true;
}
@@ -5579,7 +5598,7 @@
// Make sure we do this before calling onCreate so that we can capture the
// complete application startup.
if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
- BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE);
+ BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
}
// Install the Network Security Config Provider. This must happen before the application
@@ -6295,35 +6314,26 @@
// add dropbox logging to libcore
DropBox.setReporter(new DropBoxReporter());
- ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- synchronized (mResourcesManager) {
- // We need to apply this change to the resources
- // immediately, because upon returning the view
- // hierarchy will be informed about it.
- if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
- updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
- mResourcesManager.getConfiguration().getLocales());
+ ViewRootImpl.ConfigChangedCallback configChangedCallback
+ = (Configuration globalConfig) -> {
+ synchronized (mResourcesManager) {
+ // We need to apply this change to the resources immediately, because upon returning
+ // the view hierarchy will be informed about it.
+ if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
+ null /* compat */)) {
+ updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
+ mResourcesManager.getConfiguration().getLocales());
- // This actually changed the resources! Tell
- // everyone about it.
- if (mPendingConfiguration == null ||
- mPendingConfiguration.isOtherSeqNewer(newConfig)) {
- mPendingConfiguration = newConfig;
-
- sendMessage(H.CONFIGURATION_CHANGED, newConfig);
- }
+ // This actually changed the resources! Tell everyone about it.
+ if (mPendingConfiguration == null
+ || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
+ mPendingConfiguration = globalConfig;
+ sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
}
}
}
- @Override
- public void onLowMemory() {
- }
- @Override
- public void onTrimMemory(int level) {
- }
- });
+ };
+ ViewRootImpl.addConfigCallback(configChangedCallback);
}
public static ActivityThread systemMain() {
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index 009c448..13f288a 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -16,13 +16,21 @@
package android.app;
+import android.os.FileUtils;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* A dex load reporter which will notify package manager of any dex file loaded
@@ -37,15 +45,60 @@
/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
private static final String TAG = "DexLoadReporter";
- /*package*/ static final DexLoadReporter INSTANCE = new DexLoadReporter();
+ private static final DexLoadReporter INSTANCE = new DexLoadReporter();
- private DexLoadReporter() {}
+ private static final boolean DEBUG = false;
+
+ // We must guard the access to the list of data directories because
+ // we might have concurrent accesses. Apps might load dex files while
+ // new data dirs are registered (due to creation of LoadedApks via
+ // create createApplicationContext).
+ @GuardedBy("mDataDirs")
+ private final Set<String> mDataDirs;
+
+ private DexLoadReporter() {
+ mDataDirs = new HashSet<>();
+ }
+
+ /*package*/ static DexLoadReporter getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Register an application data directory with the reporter.
+ * The data directories are used to determine if a dex file is secondary dex or not.
+ * Note that this method may be called multiple times for the same app, registering
+ * different data directories. This may happen when apps share the same user id
+ * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user
+ * id, and app1 loads app2 apk, then both data directories will be registered.
+ */
+ /*package*/ void registerAppDataDir(String packageName, String dataDir) {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir);
+ }
+ // TODO(calin): A few code paths imply that the data dir
+ // might be null. Investigate when that can happen.
+ if (dataDir != null) {
+ synchronized (mDataDirs) {
+ mDataDirs.add(dataDir);
+ }
+ }
+ }
@Override
public void report(List<String> dexPaths) {
if (dexPaths.isEmpty()) {
return;
}
+ // Notify the package manager about the dex loads unconditionally.
+ // The load might be for either a primary or secondary dex file.
+ notifyPackageManager(dexPaths);
+ // Check for secondary dex files and register them for profiling if
+ // possible.
+ registerSecondaryDexForProfiling(dexPaths);
+ }
+
+ private void notifyPackageManager(List<String> dexPaths) {
String packageName = ActivityThread.currentPackageName();
try {
ActivityThread.getPackageManager().notifyDexLoad(
@@ -54,4 +107,62 @@
Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
}
}
+
+ private void registerSecondaryDexForProfiling(List<String> dexPaths) {
+ if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
+ return;
+ }
+ // Make a copy of the current data directories so that we don't keep the lock
+ // while registering for profiling. The registration will perform I/O to
+ // check for or create the profile.
+ String[] dataDirs;
+ synchronized (mDataDirs) {
+ dataDirs = mDataDirs.toArray(new String[0]);
+ }
+ for (String dexPath : dexPaths) {
+ registerSecondaryDexForProfiling(dexPath, dataDirs);
+ }
+ }
+
+ private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) {
+ if (!isSecondaryDexFile(dexPath, dataDirs)) {
+ // The dex path is not a secondary dex file. Nothing to do.
+ return;
+ }
+ File secondaryProfile = getSecondaryProfileFile(dexPath);
+ try {
+ // Create the profile if not already there.
+ // Returns true if the file was created, false if the file already exists.
+ // or throws exceptions in case of errors.
+ boolean created = secondaryProfile.createNewFile();
+ if (DEBUG && created) {
+ Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile);
+ }
+ } catch (IOException ex) {
+ Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile +
+ ":" + ex.getMessage());
+ // Don't move forward with the registration if we failed to create the profile.
+ return;
+ }
+
+ VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath });
+ }
+
+ // A dex file is a secondary dex file if it is in any of the registered app
+ // data directories.
+ private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) {
+ for (String dataDir : dataDirs) {
+ if (FileUtils.contains(dataDir, dexPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Secondary dex profiles are stored next to the dex file and have the same
+ // name with '.prof' appended.
+ // NOTE: Keep in sync with installd.
+ private File getSecondaryProfileFile(String dexPath) {
+ return new File(dexPath + ".prof");
+ }
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 8299c50..cf41e4e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -750,6 +750,11 @@
VMRuntime.registerAppInfo(profileFile.getPath(),
codePaths.toArray(new String[codePaths.size()]));
+
+ // Register the app data directory with the reporter. It will
+ // help deciding whether or not a dex file is the primary apk or a
+ // secondary dex.
+ DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
}
/**
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a098591..870c412 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1935,7 +1935,9 @@
if (this.actions != null) {
that.actions = new Action[this.actions.length];
for(int i=0; i<this.actions.length; i++) {
- that.actions[i] = this.actions[i].clone();
+ if ( this.actions[i] != null) {
+ that.actions[i] = this.actions[i].clone();
+ }
}
}
@@ -3432,7 +3434,9 @@
* @param action The action to add.
*/
public Builder addAction(Action action) {
- mActions.add(action);
+ if (action != null) {
+ mActions.add(action);
+ }
return this;
}
@@ -3446,7 +3450,9 @@
public Builder setActions(Action... actions) {
mActions.clear();
for (int i = 0; i < actions.length; i++) {
- mActions.add(actions[i]);
+ if (actions[i] != null) {
+ mActions.add(actions[i]);
+ }
}
return this;
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 488511b..4e1e42d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1483,6 +1483,25 @@
}
/**
+ * Return the maximum LE advertising data length,
+ * if LE Extended Advertising feature is supported.
+ *
+ * @return the maximum LE advertising data length.
+ */
+ public int getLeMaximumAdvertisingDataLength() {
+ if (!getLeAccess()) return 0;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getLeMaximumAdvertisingDataLength();
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return 0;
+ }
+
+ /**
* Return true if hardware has entries available for matching beacons
*
* @return true if there are hw entries available for matching beacons
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 76ca554..b337817 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -108,6 +108,7 @@
boolean isLeCodedPhySupported();
boolean isLeExtendedAdvertisingSupported();
boolean isLePeriodicAdvertisingSupported();
+ int getLeMaximumAdvertisingDataLength();
BluetoothActivityEnergyInfo reportActivityInfo();
/**
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 33fedc7..29f29e7 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -50,14 +50,6 @@
void stopScan(in int scannerId);
void flushPendingBatchResults(in int scannerId);
- void registerAdvertiser(in IAdvertiserCallback callback);
- void unregisterAdvertiser(in int advertiserId);
- void startMultiAdvertising(in int advertiserId,
- in AdvertiseData advertiseData,
- in AdvertiseData scanResponse,
- in AdvertiseSettings settings);
- void stopMultiAdvertising(in int advertiserId);
-
void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData,
in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters,
in AdvertiseData periodicData, in IAdvertisingSetCallback callback);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index e03c947..c9f1d7a 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.util.Log;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -60,11 +61,12 @@
private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
private BluetoothAdapter mBluetoothAdapter;
- private final Map<AdvertiseCallback, AdvertiseCallbackWrapper>
- mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>();
+ private final Map<AdvertiseCallback, AdvertisingSetCallback>
+ mLegacyAdvertisers = new HashMap<>();
private final Map<AdvertisingSetCallback, IAdvertisingSetCallback>
- advertisingSetCallbackWrappers = new HashMap<>();
- private final Map<Integer, AdvertisingSet> advertisingSets = new HashMap<>();
+ mCallbackWrappers = Collections.synchronizedMap(new HashMap<>());
+ private final Map<Integer, AdvertisingSet>
+ mAdvertisingSets = Collections.synchronizedMap(new HashMap<>());
/**
* Use BluetoothAdapter.getLeAdvertiser() instead.
@@ -109,7 +111,7 @@
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
- synchronized (mLeAdvertisers) {
+ synchronized (mLegacyAdvertisers) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -120,25 +122,65 @@
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
return;
}
- if (mLeAdvertisers.containsKey(callback)) {
+ if (mLegacyAdvertisers.containsKey(callback)) {
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
return;
}
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
- postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
- return;
+ AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
+ parameters.setLegacyMode(true);
+ parameters.setConnectable(isConnectable);
+ parameters.setTimeout(settings.getTimeout());
+ if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) {
+ parameters.setInterval(1600); // 1s
+ } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) {
+ parameters.setInterval(400); // 250ms
+ } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) {
+ parameters.setInterval(160); // 100ms
}
- AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
- scanResponse, settings, gatt);
- wrapper.startRegisteration();
+
+ if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) {
+ parameters.setTxPowerLevel(-21);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) {
+ parameters.setTxPowerLevel(-15);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {
+ parameters.setTxPowerLevel(-7);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
+ parameters.setTxPowerLevel(1);
+ }
+
+ AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings);
+ mLegacyAdvertisers.put(callback, wrapped);
+ startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null,
+ wrapped);
}
}
+ AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
+ return new AdvertisingSetCallback() {
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int status) {
+ if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+ postStartFailure(callback, status);
+ return;
+ }
+
+ postStartSuccess(callback, settings);
+ }
+
+ /* Legacy advertiser is disabled on timeout */
+ public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) {
+ if (enabled == true) {
+ Log.e(TAG, "Legacy advertiser should be only disabled on timeout," +
+ " but was enabled!");
+ return;
+ }
+
+ stopAdvertising(callback);
+ }
+
+ };
+ }
+
/**
* Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
* {@link BluetoothLeAdvertiser#startAdvertising}.
@@ -148,20 +190,21 @@
* @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
*/
public void stopAdvertising(final AdvertiseCallback callback) {
- synchronized (mLeAdvertisers) {
+ synchronized (mLegacyAdvertisers) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
- AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback);
+ AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback);
if (wrapper == null) return;
- wrapper.stopAdvertising();
+
+ stopAdvertisingSet(wrapper);
}
}
/**
* Creates a new advertising set. If operation succeed, device will start advertising. This
* method returns immediately, the operation status is delivered through
- * {@code callback.onNewAdvertisingSet()}.
+ * {@code callback.onAdvertisingSetStarted()}.
* <p>
* @param parameters advertising set parameters.
* @param advertiseData Advertisement data to be broadcasted.
@@ -180,7 +223,7 @@
/**
* Creates a new advertising set. If operation succeed, device will start advertising. This
* method returns immediately, the operation status is delivered through
- * {@code callback.onNewAdvertisingSet()}.
+ * {@code callback.onAdvertisingSetStarted()}.
* <p>
* @param parameters advertising set parameters.
* @param advertiseData Advertisement data to be broadcasted.
@@ -209,7 +252,10 @@
}
IAdvertisingSetCallback wrapped = wrap(callback, handler);
- advertisingSetCallbackWrappers.put(callback, wrapped);
+ if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) {
+ throw new IllegalArgumentException(
+ "callback instance already associated with advertising");
+ }
try {
gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
@@ -229,10 +275,9 @@
throw new IllegalArgumentException("callback cannot be null");
}
- IAdvertisingSetCallback wrapped = advertisingSetCallbackWrappers.remove(callback);
+ IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback);
if (wrapped == null) {
- throw new IllegalArgumentException(
- "callback does not represent valid registered callback.");
+ return;
}
IBluetoothGatt gatt;
@@ -251,7 +296,9 @@
* @hide
*/
public void cleanup() {
- mLeAdvertisers.clear();
+ mLegacyAdvertisers.clear();
+ mCallbackWrappers.clear();
+ mAdvertisingSets.clear();
}
// Compute the size of advertisement data or scan resp
@@ -317,13 +364,13 @@
public void run() {
if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
callback.onAdvertisingSetStarted(null, status);
- advertisingSetCallbackWrappers.remove(callback);
+ mCallbackWrappers.remove(callback);
return;
}
AdvertisingSet advertisingSet =
new AdvertisingSet(advertiserId, mBluetoothManager);
- advertisingSets.put(advertiserId, advertisingSet);
+ mAdvertisingSets.put(advertiserId, advertisingSet);
callback.onAdvertisingSetStarted(advertisingSet, status);
}
});
@@ -333,10 +380,10 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingSetStopped(advertisingSet);
- advertisingSets.remove(advertiserId);
- advertisingSetCallbackWrappers.remove(callback);
+ mAdvertisingSets.remove(advertiserId);
+ mCallbackWrappers.remove(callback);
}
});
}
@@ -345,7 +392,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingEnabled(advertisingSet, enabled, status);
}
});
@@ -355,7 +402,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingDataSet(advertisingSet, status);
}
});
@@ -365,7 +412,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onScanResponseDataSet(advertisingSet, status);
}
});
@@ -375,7 +422,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingParametersUpdated(advertisingSet, status);
}
});
@@ -385,7 +432,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
}
});
@@ -395,7 +442,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingDataSet(advertisingSet, status);
}
});
@@ -405,7 +452,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingEnable(advertisingSet, enable, status);
}
});
@@ -413,144 +460,6 @@
};
}
- /**
- * Bluetooth GATT interface callbacks for advertising.
- */
- private class AdvertiseCallbackWrapper extends IAdvertiserCallback.Stub {
- private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
- private final AdvertiseCallback mAdvertiseCallback;
- private final AdvertiseData mAdvertisement;
- private final AdvertiseData mScanResponse;
- private final AdvertiseSettings mSettings;
- private final IBluetoothGatt mBluetoothGatt;
-
- // mAdvertiserId -1: not registered
- // -2: advertise stopped or registration timeout
- // >=0: registered and advertising started
- private int mAdvertiserId;
- private boolean mIsAdvertising = false;
- private int registrationError = AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR;
-
- public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- AdvertiseSettings settings,
- IBluetoothGatt bluetoothGatt) {
- mAdvertiseCallback = advertiseCallback;
- mAdvertisement = advertiseData;
- mScanResponse = scanResponse;
- mSettings = settings;
- mBluetoothGatt = bluetoothGatt;
- mAdvertiserId = -1;
- }
-
- public void startRegisteration() {
- synchronized (this) {
- if (mAdvertiserId == -2) return;
-
- try {
- mBluetoothGatt.registerAdvertiser(this);
- wait(LE_CALLBACK_TIMEOUT_MILLIS);
- } catch (InterruptedException | RemoteException e) {
- Log.e(TAG, "Failed to start registeration", e);
- }
- if (mAdvertiserId >= 0 && mIsAdvertising) {
- mLeAdvertisers.put(mAdvertiseCallback, this);
- } else if (mAdvertiserId < 0) {
-
- // Registration timeout, reset mClientIf to -2 so no subsequent operations can
- // proceed.
- if (mAdvertiserId == -1) mAdvertiserId = -2;
- // Post internal error if registration failed.
- postStartFailure(mAdvertiseCallback, registrationError);
- } else {
- // Unregister application if it's already registered but advertise failed.
- try {
- mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -2;
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when unregistering", e);
- }
- }
- }
- }
-
- public void stopAdvertising() {
- synchronized (this) {
- try {
- mBluetoothGatt.stopMultiAdvertising(mAdvertiserId);
- wait(LE_CALLBACK_TIMEOUT_MILLIS);
- } catch (InterruptedException | RemoteException e) {
- Log.e(TAG, "Failed to stop advertising", e);
- }
- // Advertise callback should have been removed from LeAdvertisers when
- // onMultiAdvertiseCallback was called. In case onMultiAdvertiseCallback is never
- // invoked and wait timeout expires, remove callback here.
- if (mLeAdvertisers.containsKey(mAdvertiseCallback)) {
- mLeAdvertisers.remove(mAdvertiseCallback);
- }
- }
- }
-
- /**
- * Advertiser interface registered - app is ready to go
- */
- @Override
- public void onAdvertiserRegistered(int status, int advertiserId) {
- Log.d(TAG, "onAdvertiserRegistered() - status=" + status + " advertiserId=" + advertiserId);
- synchronized (this) {
- if (status == BluetoothGatt.GATT_SUCCESS) {
- try {
- if (mAdvertiserId == -2) {
- // Registration succeeds after timeout, unregister advertiser.
- mBluetoothGatt.unregisterAdvertiser(advertiserId);
- } else {
- mAdvertiserId = advertiserId;
- mBluetoothGatt.startMultiAdvertising(mAdvertiserId, mAdvertisement,
- mScanResponse, mSettings);
- }
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "failed to start advertising", e);
- }
- } else if (status == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
- registrationError = status;
- }
- // Registration failed.
- mAdvertiserId = -2;
- notifyAll();
- }
- }
-
- @Override
- public void onMultiAdvertiseCallback(int status, boolean isStart,
- AdvertiseSettings settings) {
- synchronized (this) {
- if (isStart) {
- if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
- // Start success
- mIsAdvertising = true;
- postStartSuccess(mAdvertiseCallback, settings);
- } else {
- // Start failure.
- postStartFailure(mAdvertiseCallback, status);
- }
- } else {
- // unregister advertiser for stop.
- try {
- mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -2;
- mIsAdvertising = false;
- mLeAdvertisers.remove(mAdvertiseCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when unregistering", e);
- }
- }
- notifyAll();
- }
-
- }
- }
-
private void postStartFailure(final AdvertiseCallback callback, final int error) {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 8bc65af..e3b97e8 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -100,6 +100,8 @@
private final CameraCharacteristics mCharacteristics;
private final int mTotalPartialCount;
+ private static final long NANO_PER_SECOND = 1000000000; //ns
+
/**
* A list tracking request and its expected last regular frame number and last reprocess frame
* number. Updated when calling ICameraDeviceUser methods.
@@ -1239,6 +1241,14 @@
private final List<CaptureRequest> mRequestList;
private final Handler mHandler;
private final int mSessionId;
+ /**
+ * <p>Determine if the callback holder is for a constrained high speed request list that
+ * expects batched capture results. Capture results will be batched if the request list
+ * is interleaved with preview and video requests. Capture results won't be batched if the
+ * request list only contains preview requests, or if the request doesn't belong to a
+ * constrained high speed list.
+ */
+ private final boolean mHasBatchedOutputs;
CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Handler handler, boolean repeating, int sessionId) {
@@ -1251,6 +1261,25 @@
mRequestList = new ArrayList<CaptureRequest>(requestList);
mCallback = callback;
mSessionId = sessionId;
+
+ // Check whether this callback holder is for batched outputs.
+ // The logic here should match createHighSpeedRequestList.
+ boolean hasBatchedOutputs = true;
+ for (int i = 0; i < requestList.size(); i++) {
+ CaptureRequest request = requestList.get(i);
+ if (!request.isPartOfCRequestList()) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ if (i == 0) {
+ Collection<Surface> targets = request.getTargets();
+ if (targets.size() != 2) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ }
+ }
+ mHasBatchedOutputs = hasBatchedOutputs;
}
public boolean isRepeating() {
@@ -1288,6 +1317,14 @@
public int getSessionId() {
return mSessionId;
}
+
+ public int getRequestCount() {
+ return mRequestList.size();
+ }
+
+ public boolean hasBatchedOutputs() {
+ return mHasBatchedOutputs;
+ }
}
/**
@@ -1777,10 +1814,27 @@
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()) {
- holder.getCallback().onCaptureStarted(
- CameraDeviceImpl.this,
- holder.getRequest(resultExtras.getSubsequenceId()),
- timestamp, frameNumber);
+ final int subsequenceId = resultExtras.getSubsequenceId();
+ final CaptureRequest request = holder.getRequest(subsequenceId);
+
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureStarted for requests within the batch
+ final Range<Integer> fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ timestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper(),
+ frameNumber - (subsequenceId - i));
+ }
+ } else {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(resultExtras.getSubsequenceId()),
+ timestamp, frameNumber);
+ }
}
}
});
@@ -1845,46 +1899,91 @@
Runnable resultDispatch = null;
CaptureResult finalResult;
+ // Make a copy of the native metadata before it gets moved to a CaptureResult
+ // object.
+ final CameraMetadataNative resultCopy;
+ if (holder.hasBatchedOutputs()) {
+ resultCopy = new CameraMetadataNative(result);
+ } else {
+ resultCopy = null;
+ }
// Either send a partial result or the final capture completed result
if (isPartialResult) {
final CaptureResult resultAsCapture =
new CaptureResult(result, request, resultExtras);
-
// Partial result
resultDispatch = new Runnable() {
@Override
public void run() {
- if (!CameraDeviceImpl.this.isClosed()){
- holder.getCallback().onCaptureProgressed(
- CameraDeviceImpl.this,
- request,
- resultAsCapture);
+ if (!CameraDeviceImpl.this.isClosed()) {
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureProgressed for requests within
+ // the batch.
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ CameraMetadataNative resultLocal =
+ new CameraMetadataNative(resultCopy);
+ CaptureResult resultInBatch = new CaptureResult(
+ resultLocal, holder.getRequest(i), resultExtras);
+
+ holder.getCallback().onCaptureProgressed(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ resultInBatch);
+ }
+ } else {
+ holder.getCallback().onCaptureProgressed(
+ CameraDeviceImpl.this,
+ request,
+ resultAsCapture);
+ }
}
}
};
-
finalResult = resultAsCapture;
} else {
List<CaptureResult> partialResults =
mFrameNumberTracker.popPartialResults(frameNumber);
+ final long sensorTimestamp =
+ result.get(CaptureResult.SENSOR_TIMESTAMP);
+ final Range<Integer> fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ final int subsequenceId = resultExtras.getSubsequenceId();
final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result,
request, resultExtras, partialResults, holder.getSessionId());
-
// Final capture result
resultDispatch = new Runnable() {
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()){
- holder.getCallback().onCaptureCompleted(
- CameraDeviceImpl.this,
- request,
- resultAsCapture);
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureCompleted for requests within
+ // the batch.
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ resultCopy.set(CaptureResult.SENSOR_TIMESTAMP,
+ sensorTimestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper());
+ CameraMetadataNative resultLocal =
+ new CameraMetadataNative(resultCopy);
+ TotalCaptureResult resultInBatch = new TotalCaptureResult(
+ resultLocal, holder.getRequest(i), resultExtras,
+ partialResults, holder.getSessionId());
+
+ holder.getCallback().onCaptureCompleted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ resultInBatch);
+ }
+ } else {
+ holder.getCallback().onCaptureCompleted(
+ CameraDeviceImpl.this,
+ request,
+ resultAsCapture);
+ }
}
}
};
-
finalResult = resultAsCapture;
}
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
index fc7d0d2..8964893 100644
--- a/core/java/android/hardware/radio/RadioModule.java
+++ b/core/java/android/hardware/radio/RadioModule.java
@@ -16,6 +16,8 @@
package android.hardware.radio;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -23,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.UUID;
/**
@@ -76,6 +79,8 @@
public native int getProgramInformation(RadioManager.ProgramInfo[] info);
+ public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
+
public native boolean isAntennaConnected();
public native boolean hasControl();
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 5c82555..c8034eb 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -16,6 +16,8 @@
package android.hardware.radio;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -23,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.UUID;
/**
@@ -209,6 +212,20 @@
public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
/**
+ * Get the list of discovered radio stations.
+ *
+ * To get the full list, set filter to null or empty string. Otherwise, client application
+ * must verify vendor product/name before setting this parameter to anything else.
+ *
+ * @param filter vendor-specific selector for radio stations.
+ * @return a list of radio stations.
+ * @throws IllegalStateException if the scan is in progress or has not been started.
+ * @throws IllegalArgumentException if the filter argument is not valid.
+ * @hide FutureFeature
+ */
+ public abstract @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
+
+ /**
* Get current antenna connection state for current configuration.
* Only valid if a configuration has been applied.
* @return {@code true} if the antenna is connected, {@code false} otherwise.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 70e0461..f55c7cf 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -149,13 +149,13 @@
// Notification cancellation reasons
/** Notification was canceled by the status bar reporting a notification click. */
- public static final int REASON_DELEGATE_CLICK = 1;
+ public static final int REASON_CLICK = 1;
/** Notification was canceled by the status bar reporting a user dismissal. */
- public static final int REASON_DELEGATE_CANCEL = 2;
+ public static final int REASON_CANCEL = 2;
/** Notification was canceled by the status bar reporting a user dismiss all. */
- public static final int REASON_DELEGATE_CANCEL_ALL = 3;
+ public static final int REASON_CANCEL_ALL = 3;
/** Notification was canceled by the status bar reporting an inflation error. */
- public static final int REASON_DELEGATE_ERROR = 4;
+ public static final int REASON_ERROR = 4;
/** Notification was canceled by the package manager modifying the package. */
public static final int REASON_PACKAGE_CHANGED = 5;
/** Notification was canceled by the owning user context being stopped. */
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 10e4177..6034c18 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -50,5 +50,13 @@
* @param enabled true if the device should be placed in persistent VR mode.
*/
void setPersistentVrModeEnabled(in boolean enabled);
+
+ /**
+ * Return current virtual display id.
+ *
+ * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+ * currently, else return the display id of the virtual display
+ */
+ int getCompatibilityDisplayId();
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 483a49b..6bbb0ff 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -18,11 +18,11 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.util.MergedConfiguration;
import android.view.WindowInsets;
import com.android.internal.R;
import com.android.internal.os.HandlerCaller;
-import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
@@ -32,7 +32,6 @@
import android.app.WallpaperManager;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -55,7 +54,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import java.io.FileDescriptor;
@@ -169,7 +167,7 @@
final Rect mFinalSystemInsets = new Rect();
final Rect mFinalStableInsets = new Rect();
final Rect mBackdropFrame = new Rect();
- final Configuration mConfiguration = new Configuration();
+ final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
final WindowManager.LayoutParams mLayout
= new WindowManager.LayoutParams();
@@ -288,7 +286,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout,
+ MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
boolean alwaysConsumeNavBar, int displayId) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0, outsets);
@@ -568,7 +566,8 @@
out.print(mVisibleInsets.toShortString());
out.print(" mWinFrame="); out.print(mWinFrame.toShortString());
out.print(" mContentInsets="); out.println(mContentInsets.toShortString());
- out.print(prefix); out.print("mConfiguration="); out.println(mConfiguration);
+ out.print(prefix); out.print("mConfiguration=");
+ out.println(mMergedConfiguration.getMergedConfiguration());
out.print(prefix); out.print("mLayout="); out.println(mLayout);
synchronized (mLock) {
out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset);
@@ -695,7 +694,7 @@
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mConfiguration, mSurfaceHolder.mSurface);
+ mMergedConfiguration, mSurfaceHolder.mSurface);
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java
new file mode 100644
index 0000000..e5aa2b5
--- /dev/null
+++ b/core/java/android/util/LauncherIcons.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons.
+ * @hide
+ */
+public final class LauncherIcons {
+
+ private final Paint mPaint = new Paint();
+ private final Canvas mCanvas = new Canvas();
+
+ private static final int KEY_SHADOW_ALPHA = 61;
+ private static final int AMBIENT_SHADOW_ALPHA = 30;
+ private static final float BLUR_FACTOR = 0.5f / 48;
+ private int mShadowInset;
+ private Bitmap mShadowBitmap;
+ private int mIconSize;
+ private Resources mRes;
+
+ public LauncherIcons(Context context) {
+ mRes = context.getResources();
+ DisplayMetrics metrics = mRes.getDisplayMetrics();
+ mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT;
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+ mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size);
+ }
+
+ /**
+ * Draw the drawable into a bitmap.
+ */
+ public Bitmap createIconBitmap(Drawable icon) {
+ final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888);
+ mPaint.setAlpha(255);
+ mCanvas.setBitmap(bitmap);
+ int iconInset = 0;
+ if (mShadowBitmap != null) {
+ mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint);
+ iconInset = mShadowInset;
+ }
+
+ icon.setBounds(iconInset, iconInset, mIconSize - iconInset,
+ mIconSize - iconInset);
+ icon.draw(mCanvas);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ public Drawable wrapIconDrawableWithShadow(Drawable drawable) {
+ if (!(drawable instanceof AdaptiveIconDrawable)) {
+ return drawable;
+ }
+ AdaptiveIconDrawable d =
+ (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate();
+ getShadowBitmap(d);
+ Bitmap iconbitmap = createIconBitmap(d);
+ return new BitmapDrawable(mRes, iconbitmap);
+ }
+
+ private Bitmap getShadowBitmap(AdaptiveIconDrawable d) {
+ if (mShadowBitmap != null) {
+ return mShadowBitmap;
+ }
+
+ int shadowSize = mIconSize - mShadowInset;
+ mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8);
+ mCanvas.setBitmap(mShadowBitmap);
+
+ // Draw key shadow
+ mPaint.setColor(Color.TRANSPARENT);
+ float blur = BLUR_FACTOR * mIconSize;
+ mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24);
+ d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset);
+ mCanvas.drawPath(d.getIconMask(), mPaint);
+
+ // Draw ambient shadow
+ mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24);
+ d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize);
+ mCanvas.drawPath(d.getIconMask(), mPaint);
+ mPaint.clearShadowLayer();
+
+ return mShadowBitmap;
+ }
+}
diff --git a/core/java/android/util/MergedConfiguration.aidl b/core/java/android/util/MergedConfiguration.aidl
new file mode 100644
index 0000000..c24dbbe
--- /dev/null
+++ b/core/java/android/util/MergedConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.util;
+
+parcelable MergedConfiguration;
\ No newline at end of file
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
new file mode 100644
index 0000000..d94af8a
--- /dev/null
+++ b/core/java/android/util/MergedConfiguration.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container that holds global and override config and their merge product.
+ * Merged configuration updates automatically whenever global or override configs are updated via
+ * setters.
+ *
+ * {@hide}
+ */
+public class MergedConfiguration implements Parcelable {
+
+ private Configuration mGlobalConfig = new Configuration();
+ private Configuration mOverrideConfig = new Configuration();
+ private Configuration mMergedConfig = new Configuration();
+
+ public MergedConfiguration() {
+ }
+
+ public MergedConfiguration(Configuration globalConfig, Configuration overrideConfig) {
+ setConfiguration(globalConfig, overrideConfig);
+ }
+
+ public MergedConfiguration(MergedConfiguration mergedConfiguration) {
+ setConfiguration(mergedConfiguration.getGlobalConfiguration(),
+ mergedConfiguration.getOverrideConfiguration());
+ }
+
+ private MergedConfiguration(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mGlobalConfig, flags);
+ dest.writeParcelable(mOverrideConfig, flags);
+ dest.writeParcelable(mMergedConfig, flags);
+ }
+
+ public void readFromParcel(Parcel source) {
+ mGlobalConfig = source.readParcelable(Configuration.class.getClassLoader());
+ mOverrideConfig = source.readParcelable(Configuration.class.getClassLoader());
+ mMergedConfig = source.readParcelable(Configuration.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<MergedConfiguration> CREATOR = new Creator<MergedConfiguration>() {
+ @Override
+ public MergedConfiguration createFromParcel(Parcel in) {
+ return new MergedConfiguration(in);
+ }
+
+ @Override
+ public MergedConfiguration[] newArray(int size) {
+ return new MergedConfiguration[size];
+ }
+ };
+
+ /**
+ * Update global and override configurations.
+ * Merged configuration will automatically be updated.
+ * @param globalConfig New global configuration.
+ * @param overrideConfig New override configuration.
+ */
+ public void setConfiguration(Configuration globalConfig, Configuration overrideConfig) {
+ mGlobalConfig.setTo(globalConfig);
+ mOverrideConfig.setTo(overrideConfig);
+ updateMergedConfig();
+ }
+
+ /**
+ * @return Stored global configuration value.
+ */
+ @NonNull
+ public Configuration getGlobalConfiguration() {
+ return mGlobalConfig;
+ }
+
+ /**
+ * @return Stored override configuration value.
+ */
+ public Configuration getOverrideConfiguration() {
+ return mOverrideConfig;
+ }
+
+ /**
+ * @return Stored merged configuration value.
+ */
+ public Configuration getMergedConfiguration() {
+ return mMergedConfig;
+ }
+
+ /** Update merged config when global or override config changes. */
+ private void updateMergedConfig() {
+ mMergedConfig.setTo(mGlobalConfig);
+ mMergedConfig.updateFrom(mOverrideConfig);
+ }
+}
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index e59937d..ca54bef 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -16,7 +16,6 @@
package android.view;
-import android.content.ComponentCallbacks;
import android.content.res.Configuration;
import java.text.BreakIterator;
@@ -65,7 +64,7 @@
}
static class CharacterTextSegmentIterator extends AbstractTextSegmentIterator
- implements ComponentCallbacks {
+ implements ViewRootImpl.ConfigChangedCallback {
private static CharacterTextSegmentIterator sInstance;
private Locale mLocale;
@@ -144,19 +143,14 @@
}
@Override
- public void onConfigurationChanged(Configuration newConfig) {
- Locale locale = newConfig.locale;
+ public void onConfigurationChanged(Configuration globalConfig) {
+ final Locale locale = globalConfig.getLocales().get(0);
if (!mLocale.equals(locale)) {
mLocale = locale;
onLocaleChanged(locale);
}
}
- @Override
- public void onLowMemory() {
- /* ignore */
- }
-
protected void onLocaleChanged(Locale locale) {
mImpl = BreakIterator.getCharacterInstance(locale);
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 14b2abe..611cc63 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,7 +17,6 @@
package android.view;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -26,6 +25,7 @@
import android.view.MotionEvent;
import com.android.internal.os.IResultReceiver;
+import android.util.MergedConfiguration;
/**
* API back to a client window that the Window Manager uses to inform it of
@@ -49,8 +49,8 @@
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
- in Configuration newConfig, in Rect backDropFrame, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId);
+ in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
+ boolean forceLayout, boolean alwaysConsumeNavBar, int displayId);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7e6af11..51d6514 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -11,17 +11,17 @@
** 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
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
package android.view;
import android.content.ClipData;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
+import android.util.MergedConfiguration;
import android.view.InputChannel;
import android.view.IWindow;
import android.view.IWindowId;
@@ -83,9 +83,9 @@
* treat as real display. Example of such area is a chin in some models of wearable devices.
* @param outBackdropFrame Rect which is used draw the resizing background during a resize
* operation.
- * @param outConfiguration New configuration of window, if it is now
- * becoming visible and the global configuration has changed since it
- * was last displayed.
+ * @param outMergedConfiguration New config container that holds global, override and merged
+ * config for window, if it is now becoming visible and the merged configuration has changed
+ * since it was last displayed.
* @param outSurface Object in which is placed the new display surface.
*
* @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
@@ -95,8 +95,8 @@
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out Rect outFrame, out Rect outOverscanInsets,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
- out Rect outOutsets, out Rect outBackdropFrame, out Configuration outConfig,
- out Surface outSurface);
+ out Rect outOutsets, out Rect outBackdropFrame,
+ out MergedConfiguration outMergedConfiguration, out Surface outSurface);
/*
* Notify the window manager that an application is relaunching and
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6d320ef..824e035 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,8 +16,9 @@
package android.view;
-import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
import android.content.Context;
@@ -28,6 +29,7 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
@@ -777,6 +779,31 @@
}
/**
+ * This method still exists only for compatibility reasons because some applications have relied
+ * on this method via reflection. See Issue 36345857 for details.
+ *
+ * @deprecated No platform code is using this method anymore.
+ * @hide
+ */
+ @Deprecated
+ public void setWindowType(int type) {
+ if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ throw new UnsupportedOperationException(
+ "SurfaceView#setWindowType() has never been a public API.");
+ }
+
+ if (type == TYPE_APPLICATION_PANEL) {
+ Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
+ + "just to make the SurfaceView to be placed on top of its window, you must "
+ + "call setZOrderOnTop(true) instead.", new Throwable());
+ setZOrderOnTop(true);
+ return;
+ }
+ Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
+ + "type=" + type, new Throwable());
+ }
+
+ /**
* Check to see if the surface has fixed size dimensions or if the surface's
* dimensions are dimensions are dependent on its current layout.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 80f6c32..6cddbac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7445,8 +7445,11 @@
* </pre>
*
* @param value value to be autofilled.
+ *
+ * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
*/
- public void autofill(@SuppressWarnings("unused") AutofillValue value) {
+ public boolean autofill(@SuppressWarnings("unused") AutofillValue value) {
+ return false;
}
/**
@@ -7457,9 +7460,12 @@
*
* @param value value to be autofilled.
* @param virtualId id identifying the virtual child inside the custom view.
+ *
+ * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
*/
- public void autofillVirtual(@SuppressWarnings("unused") int virtualId,
+ public boolean autofillVirtual(@SuppressWarnings("unused") int virtualId,
@SuppressWarnings("unused") AutofillValue value) {
+ return false;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ed42385..048b7c2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
@@ -28,10 +29,10 @@
import android.animation.LayoutTransition;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.app.ResourcesManager;
import android.content.ClipData;
import android.content.ClipDescription;
-import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
@@ -67,6 +68,7 @@
import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.TypedValue;
@@ -161,7 +163,44 @@
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
static boolean sFirstDrawComplete = false;
- static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
+ /**
+ * Callback for notifying about global configuration changes.
+ */
+ public interface ConfigChangedCallback {
+
+ /** Notifies about global config change. */
+ void onConfigurationChanged(Configuration globalConfig);
+ }
+
+ private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>();
+
+ /**
+ * Callback for notifying activities about override configuration changes.
+ */
+ public interface ActivityConfigCallback {
+
+ /**
+ * Notifies about override config change and/or move to different display.
+ * @param overrideConfig New override config to apply to activity.
+ * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed.
+ */
+ void onConfigurationChanged(Configuration overrideConfig, int newDisplayId);
+ }
+
+ /**
+ * Callback used to notify corresponding activity about override configuration change and make
+ * sure that all resources are set correctly before updating the ViewRootImpl's internal state.
+ */
+ private ActivityConfigCallback mActivityConfigCallback;
+
+ /**
+ * Used when configuration change first updates the config of corresponding activity.
+ * In that case we receive a call back from {@link ActivityThread} and this flag is used to
+ * preserve the initial value.
+ *
+ * @see #performConfigurationChange(Configuration, Configuration, boolean, int)
+ */
+ private boolean mForceNextConfigUpdate;
/**
* Signals that compatibility booleans have been initialized according to
@@ -344,8 +383,12 @@
private WindowInsets mLastWindowInsets;
- final Configuration mLastConfiguration = new Configuration();
- final Configuration mPendingConfiguration = new Configuration();
+ /** Last applied configuration obtained from resources. */
+ private final Configuration mLastConfigurationFromResources = new Configuration();
+ /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
+ private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration();
+ /** Configurations waiting to be applied. */
+ private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration();
boolean mScrollMayChange;
@SoftInputModeFlags
@@ -480,12 +523,18 @@
}
}
- public static void addConfigCallback(ComponentCallbacks callback) {
+ /** Add static config callback to be notified about global config changes. */
+ public static void addConfigCallback(ConfigChangedCallback callback) {
synchronized (sConfigCallbacks) {
sConfigCallbacks.add(callback);
}
}
+ /** Add activity config callback to be notified about override config changes. */
+ public void setActivityConfigCallback(ActivityConfigCallback callback) {
+ mActivityConfigCallback = callback;
+ }
+
public void addWindowCallbacks(WindowCallbacks callback) {
if (USE_MT_RENDERER) {
synchronized (mWindowCallbacks) {
@@ -1558,6 +1607,7 @@
mFullRedrawNeeded = true;
mLayoutRequested = true;
+ final Configuration config = mContext.getResources().getConfiguration();
if (shouldUseDisplaySize(lp)) {
// NOTE -- system code, won't try to do compat mode.
Point size = new Point();
@@ -1565,7 +1615,6 @@
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
- Configuration config = mContext.getResources().getConfiguration();
desiredWindowWidth = dipToPx(config.screenWidthDp);
desiredWindowHeight = dipToPx(config.screenHeightDp);
}
@@ -1577,11 +1626,11 @@
mAttachInfo.mHasWindowFocus = false;
mAttachInfo.mWindowVisibility = viewVisibility;
mAttachInfo.mRecomputeGlobalAttributes = false;
- mLastConfiguration.setTo(host.getResources().getConfiguration());
+ mLastConfigurationFromResources.setTo(config);
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
// Set the layout direction if it has not been set before (inherit is the default)
if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
- host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+ host.setLayoutDirection(config.getLayoutDirection());
}
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
@@ -1826,11 +1875,14 @@
+ " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
- if (mPendingConfiguration.seq != 0) {
+ final Configuration pendingMergedConfig =
+ mPendingMergedConfiguration.getMergedConfiguration();
+ if (pendingMergedConfig.seq != 0) {
if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
- + mPendingConfiguration);
- updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
- mPendingConfiguration.seq = 0;
+ + pendingMergedConfig);
+ performConfigurationChange(mPendingMergedConfiguration, !mFirst,
+ INVALID_DISPLAY /* same display */);
+ pendingMergedConfig.seq = 0;
updatedConfiguration = true;
}
@@ -3388,43 +3440,82 @@
unscheduleTraversals();
}
- void updateConfiguration(Configuration config, boolean force) {
- if (DEBUG_CONFIGURATION) Log.v(mTag,
- "Applying new config to window "
- + mWindowAttributes.getTitle()
- + ": " + config);
+ /**
+ * Notifies all callbacks that configuration and/or display has changed and updates internal
+ * state.
+ * @param mergedConfiguration New global and override config in {@link MergedConfiguration}
+ * container.
+ * @param force Flag indicating if we should force apply the config.
+ * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not
+ * changed.
+ */
+ private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force,
+ int newDisplayId) {
+ if (mergedConfiguration == null) {
+ throw new IllegalArgumentException("No merged config provided.");
+ }
- CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
+ Configuration globalConfig = mergedConfiguration.getGlobalConfiguration();
+ final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration();
+ if (DEBUG_CONFIGURATION) Log.v(mTag,
+ "Applying new config to window " + mWindowAttributes.getTitle()
+ + ", globalConfig: " + globalConfig
+ + ", overrideConfig: " + overrideConfig);
+
+ final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
- config = new Configuration(config);
- ci.applyToConfiguration(mNoncompatDensity, config);
+ globalConfig = new Configuration(globalConfig);
+ ci.applyToConfiguration(mNoncompatDensity, globalConfig);
}
synchronized (sConfigCallbacks) {
for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
- sConfigCallbacks.get(i).onConfigurationChanged(config);
+ sConfigCallbacks.get(i).onConfigurationChanged(globalConfig);
}
}
- if (mView != null) {
- // At this point the resources have been updated to
- // have the most recent config, whatever that is. Use
- // the one in them which may be newer.
- final Resources localResources = mView.getResources();
- config = localResources.getConfiguration();
- if (force || mLastConfiguration.diff(config) != 0) {
- // Update the display with new DisplayAdjustments.
- mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
- mDisplay.getDisplayId(), localResources);
- final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
- final int currentLayoutDirection = config.getLayoutDirection();
- mLastConfiguration.setTo(config);
- if (lastLayoutDirection != currentLayoutDirection &&
- mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
- mView.setLayoutDirection(currentLayoutDirection);
- }
- mView.dispatchConfigurationChanged(config);
+ mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+
+ mForceNextConfigUpdate = force;
+ if (mActivityConfigCallback != null) {
+ // An activity callback is set - notify it about override configuration update.
+ // This basically initiates a round trip to ActivityThread and back, which will ensure
+ // that corresponding activity and resources are updated before updating inner state of
+ // ViewRootImpl. Eventually it will call #updateConfiguration().
+ mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
+ } else {
+ // There is no activity callback - update the configuration right away.
+ updateConfiguration();
+ }
+ mForceNextConfigUpdate = false;
+ }
+
+ /**
+ * Update display and views if last applied merged configuration changed.
+ */
+ public void updateConfiguration() {
+ if (mView == null) {
+ return;
+ }
+
+ // At this point the resources have been updated to
+ // have the most recent config, whatever that is. Use
+ // the one in them which may be newer.
+ final Resources localResources = mView.getResources();
+ final Configuration config = localResources.getConfiguration();
+ if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
+ // Update the display with new DisplayAdjustments.
+ mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
+ mDisplay.getDisplayId(), localResources);
+
+ final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
+ final int currentLayoutDirection = config.getLayoutDirection();
+ mLastConfigurationFromResources.setTo(config);
+ if (lastLayoutDirection != currentLayoutDirection
+ && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+ mView.setLayoutDirection(currentLayoutDirection);
}
+ mView.dispatchConfigurationChanged(config);
}
}
@@ -3582,13 +3673,16 @@
if (mAdded) {
SomeArgs args = (SomeArgs) msg.obj;
- if (mDisplay.getDisplayId() != args.argi3) {
- onMovedToDisplay(args.argi3);
+ final int displayId = args.argi3;
+ final boolean displayChanged = mDisplay.getDisplayId() != displayId;
+ if (displayChanged) {
+ onMovedToDisplay(displayId);
}
- Configuration config = (Configuration) args.arg4;
- if (config != null) {
- updateConfiguration(config, false);
+ final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
+ if (mergedConfiguration != null) {
+ performConfigurationChange(mergedConfiguration, false /* force */,
+ displayChanged ? displayId : INVALID_DISPLAY /* same display */);
}
final boolean framesChanged = !mWinFrame.equals(args.arg1)
@@ -3759,11 +3853,19 @@
handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj);
} break;
case MSG_UPDATE_CONFIGURATION: {
- Configuration config = (Configuration)msg.obj;
- if (config.isOtherSeqNewer(mLastConfiguration)) {
- config = mLastConfiguration;
+ Configuration config = (Configuration) msg.obj;
+ if (config.isOtherSeqNewer(
+ mLastReportedMergedConfiguration.getMergedConfiguration())) {
+ // If we already have a newer merged config applied - use its global part.
+ config = mLastReportedMergedConfiguration.getGlobalConfiguration();
}
- updateConfiguration(config, false);
+
+ // Use the newer global config and last reported override config.
+ mPendingMergedConfiguration.setConfiguration(config,
+ mLastReportedMergedConfiguration.getOverrideConfiguration());
+
+ performConfigurationChange(mPendingMergedConfiguration, false /* force */,
+ INVALID_DISPLAY /* same display */);
} break;
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
setAccessibilityFocus(null, null);
@@ -5902,7 +6004,7 @@
if (params != null) {
if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
}
- mPendingConfiguration.seq = 0;
+ mPendingMergedConfiguration.getMergedConfiguration().seq = 0;
//Log.d(mTag, ">>>>>> CALLING relayout");
if (params != null && mOrigWindowType != params.type) {
// For compatibility with old apps, don't crash here.
@@ -5918,8 +6020,8 @@
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
- mSurface);
+ mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
+ mPendingMergedConfiguration, mSurface);
mPendingAlwaysConsumeNavBar =
(relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
@@ -6199,9 +6301,9 @@
}
}
- public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
+ private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+ MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeNavBar, int displayId) {
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
@@ -6233,7 +6335,8 @@
args.arg1 = sameProcessCall ? new Rect(frame) : frame;
args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
- args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
+ args.arg4 = sameProcessCall && mergedConfiguration != null
+ ? new MergedConfiguration(mergedConfiguration) : null;
args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
@@ -7243,13 +7346,13 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropFrame, boolean forceLayout,
+ MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeNavBar, int displayId) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
- forceLayout, alwaysConsumeNavBar, displayId);
+ visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
+ backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
}
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f036b9c..b852aab 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -83,7 +83,7 @@
/** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000;
/** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000;
- private final Rect mTempRect = new Rect();
+ @NonNull private final Rect mTempRect = new Rect();
private final IAutoFillManager mService;
private IAutoFillManagerClient mServiceClient;
@@ -196,6 +196,9 @@
ensureServiceClientAddedIfNeeded();
if (!mEnabled) {
+ if (mCallback != null) {
+ mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
return;
}
@@ -241,6 +244,10 @@
ensureServiceClientAddedIfNeeded();
if (!mEnabled) {
+ if (mCallback != null) {
+ mCallback.onAutofillEventVirtual(view, childId,
+ AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
return;
}
@@ -371,8 +378,8 @@
return new AutofillId(parent.getAccessibilityViewId(), childId);
}
- private void startSession(AutofillId id, IBinder windowToken, Rect bounds,
- AutofillValue value, int flags) {
+ private void startSession(@NonNull AutofillId id, @NonNull IBinder windowToken,
+ @NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
if (DEBUG) {
Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags);
@@ -381,8 +388,8 @@
try {
mService.startSession(mContext.getActivityToken(), windowToken,
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags);
- final AutofillClient client = getClient();
+ mCallback != null, flags, mContext.getOpPackageName());
+ AutofillClient client = getClient();
if (client != null) {
client.resetableStateAvailable();
}
@@ -539,6 +546,15 @@
public static final int EVENT_INPUT_HIDDEN = 2;
/**
+ * The auto-fill input UI affordance associated with the view won't be shown because
+ * autofill is not available.
+ *
+ * <p>If the view provides its own auto-complete UI affordance but was not displaying it
+ * to avoid flickering, it could shown it upon receiving this event.
+ */
+ public static final int EVENT_INPUT_UNAVAILABLE = 3;
+
+ /**
* Called after a change in the autofill state associated with a view.
*
* @param view view associated with the change.
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 85b05e5..97210cc 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,7 +32,7 @@
boolean addClient(in IAutoFillManagerClient client, int userId);
oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
- boolean hasCallback, int flags);
+ boolean hasCallback, int flags, String packageName);
oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds,
in AutofillValue value, int flags, int userId);
oneway void finishSession(in IBinder activityToken, int userId);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 020e80a..fae5742 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -514,14 +514,15 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isList()) {
setSelection(value.getListValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+ return true;
}
@Override
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 899a824..9dc61ab 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -584,14 +584,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isToggle()) {
setChecked(value.getToggleValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index f63573f..7d04f35 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -775,14 +775,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isDate()) {
mDelegate.updateDate(value.getDateValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5e8279a..a7574c7 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -426,23 +426,24 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
int index;
if (value.isList()) {
index = value.getListValue();
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
- return;
+ return false;
}
final View child = getChildAt(index);
if (child == null) {
Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index);
- return;
+ return false;
}
check(child.getId());
+ return true;
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c5c317d..26edc43 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10028,14 +10028,17 @@
}
@Override
- public void autofill(AutofillValue value) {
+ public boolean autofill(AutofillValue value) {
if (value.isText()) {
if (isTextEditable()) {
setText(value.getTextValue(), mBufferType, true, 0);
+ return true;
}
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return false;
}
@Override
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index cfa78b5..1e97e3b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -530,14 +530,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isDate()) {
mDelegate.setDate(value.getDateValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ce51dc4..361fd3da 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,12 +16,12 @@
package com.android.internal.view;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.MergedConfiguration;
import android.view.DragEvent;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -39,8 +39,9 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
- Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) {
+ Rect stableInsets, Rect outsets, boolean reportDraw,
+ MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
+ boolean alwaysConsumeNavBar, int displayId) {
if (reportDraw) {
try {
mSession.finishDrawing(this);
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 79439e2..5553a3e 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -30,7 +30,7 @@
class SkColorFilterGlue {
public:
- static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
+ static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
SkSafeUnref(filter);
}
@@ -57,19 +57,19 @@
};
static const JNINativeMethod colorfilter_methods[] = {
- {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
+ {"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref}
};
static const JNINativeMethod porterduff_methods[] = {
- { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
+ { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
};
static const JNINativeMethod lighting_methods[] = {
- { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
+ { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
};
static const JNINativeMethod colormatrix_methods[] = {
- { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
+ { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
};
int register_android_graphics_ColorFilter(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 9660de4..956b724 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -26,7 +26,9 @@
#include <sys/un.h>
#include <unistd.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
// Static whitelist of open paths that the zygote is allowed to keep open.
@@ -65,9 +67,10 @@
return true;
}
- static const std::string kFrameworksPrefix = "/system/framework/";
- static const std::string kJarSuffix = ".jar";
- if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
+ static const char* kFrameworksPrefix = "/system/framework/";
+ static const char* kJarSuffix = ".jar";
+ if (android::base::StartsWith(path, kFrameworksPrefix)
+ && android::base::EndsWith(path, kJarSuffix)) {
return true;
}
@@ -79,28 +82,31 @@
// /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
// /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
// See AssetManager.cpp for more details on overlay-subdir.
- static const std::string kOverlayDir = "/system/vendor/overlay/";
- static const std::string kVendorOverlayDir = "/vendor/overlay";
- static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
- static const std::string kApkSuffix = ".apk";
+ static const char* kOverlayDir = "/system/vendor/overlay/";
+ static const char* kVendorOverlayDir = "/vendor/overlay";
+ static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
+ static const char* kApkSuffix = ".apk";
- if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
- || StartsWith(path, kVendorOverlayDir))
- && EndsWith(path, kApkSuffix)
+ if ((android::base::StartsWith(path, kOverlayDir)
+ || android::base::StartsWith(path, kOverlaySubdir)
+ || android::base::StartsWith(path, kVendorOverlayDir))
+ && android::base::EndsWith(path, kApkSuffix)
&& path.find("/../") == std::string::npos) {
return true;
}
- static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
- static const std::string kOverlayIdmapSuffix = ".apk@idmap";
- if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
+ static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
+ static const char* kOverlayIdmapSuffix = ".apk@idmap";
+ if (android::base::StartsWith(path, kOverlayIdmapPrefix)
+ && android::base::EndsWith(path, kOverlayIdmapSuffix)
&& path.find("/../") == std::string::npos) {
return true;
}
// All regular files that are placed under this path are whitelisted automatically.
- static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
- if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
+ static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
+ if (android::base::StartsWith(path, kZygoteWhitelistPath)
+ && path.find("/../") == std::string::npos) {
return true;
}
@@ -111,24 +117,6 @@
: whitelist_() {
}
-// TODO: Call android::base::StartsWith instead of copying the code here.
-// static
-bool FileDescriptorWhitelist::StartsWith(const std::string& str,
- const std::string& prefix) {
- return str.compare(0, prefix.size(), prefix) == 0;
-}
-
-// TODO: Call android::base::EndsWith instead of copying the code here.
-// static
-bool FileDescriptorWhitelist::EndsWith(const std::string& str,
- const std::string& suffix) {
- if (suffix.size() > str.size()) {
- return false;
- }
-
- return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
-}
-
FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
// static
@@ -174,7 +162,8 @@
}
std::string file_path;
- if (!Readlink(fd, &file_path)) {
+ const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+ if (!android::base::Readlink(fd_path, &file_path)) {
return NULL;
}
@@ -299,30 +288,6 @@
is_sock(false) {
}
-// TODO: Call android::base::Readlink instead of copying the code here.
-// static
-bool FileDescriptorInfo::Readlink(const int fd, std::string* result) {
- char path[64];
- snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
-
- // Code copied from android::base::Readlink starts here :
-
- // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
- // and truncates to whatever size you do supply, so it can't be used to query.
- // We could call lstat first, but that would introduce a race condition that
- // we couldn't detect.
- // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
- char buf[4096];
- ssize_t len = readlink(path, buf, sizeof(buf));
- if (len == -1) {
- PLOG(ERROR) << "Readlink on " << fd << " failed.";
- return false;
- }
-
- result->assign(buf, len);
- return true;
-}
-
// static
bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
sockaddr_storage ss;
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 03298c3..a39e387 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -59,10 +59,6 @@
private:
FileDescriptorWhitelist();
- static bool StartsWith(const std::string& str, const std::string& prefix);
-
- static bool EndsWith(const std::string& str, const std::string& suffix);
-
static FileDescriptorWhitelist* instance_;
std::vector<std::string> whitelist_;
@@ -99,8 +95,6 @@
FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
int fd_flags, int fs_flags, off_t offset);
- static bool Readlink(const int fd, std::string* result);
-
// Returns the locally-bound name of the socket |fd|. Returns true
// iff. all of the following hold :
//
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6e0d9dc..385f256 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1386,6 +1386,9 @@
<!-- Boolean indicating if current platform supports BLE peripheral mode -->
<bool name="config_bluetooth_le_peripheral_mode_supported">false</bool>
+ <!-- Boolean indicating if current platform supports HFP inband ringing -->
+ <bool name="config_bluetooth_hfp_inband_ringing_support">false</bool>
+
<!-- Max number of scan filters supported by blutooth controller. 0 if the
device does not support hardware scan filters-->
<integer translatable="false" name="config_bluetooth_max_scan_filters">0</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1ed069b..d1c14e9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4567,22 +4567,25 @@
<!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
<string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
- <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
- by an auto-fill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
+ <!-- Accessibility title for the autofill dialog used to select a list of options to autofill an activity. [CHAR LIMIT=NONE] -->
+ <string name="autofill_picker_accessibility_title">Autofill options</string>
+
+ <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
+ by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
<string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string>
- <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved
- by an auto-fill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+ <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
+ by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
<string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <xliff:g id="label" example="MyPass">%2$s</xliff:g>?</string>
- <!-- Label for the auto-fill save button [CHAR LIMIT=NONE] -->
+ <!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
<string name="autofill_save_yes">Save</string>
- <!-- Label for the auto-fill cancel button [CHAR LIMIT=NONE] -->
+ <!-- Label for the autofill cancel button [CHAR LIMIT=NONE] -->
<string name="autofill_save_no">No thanks</string>
- <!-- Label for the type of data being saved for auto-fill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
+ <!-- Label for the type of data being saved for autofill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_password">password</string>
- <!-- Label for the type of data being saved for auto-fill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
+ <!-- Label for the type of data being saved for autofill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_address">address</string>
- <!-- Label for the type of data being saved for auto-fill when it represents a credit card [CHAR LIMIT=NONE] -->
+ <!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_credit_card">credit card</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 07cecbc..0d4a407 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -242,6 +242,7 @@
<java-symbol type="bool" name="config_bluetooth_address_validation" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
<java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
+ <java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
<java-symbol type="bool" name="config_cellBroadcastAppLinks" />
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_enableAutoPowerModes" />
@@ -2848,6 +2849,7 @@
<java-symbol type="id" name="autofill_save_yes" />
<java-symbol type="id" name="autofill_save_close" />
<java-symbol type="string" name="autofill" />
+ <java-symbol type="string" name="autofill_picker_accessibility_title " />
<java-symbol type="string" name="autofill_save_title" />
<java-symbol type="string" name="autofill_save_title_with_type" />
<java-symbol type="string" name="autofill_save_yes" />
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index ac62bf4..0ca3729 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -28,21 +28,51 @@
*/
public class ColorFilter {
/**
- * Holds the pointer to the native SkColorFilter instance.
- *
- * @hide
+ * @deprecated Use subclass constructors directly instead.
*/
- public long native_instance;
+ @Deprecated
+ public ColorFilter() {}
+
+ /**
+ * Holds the pointer to the native SkColorFilter instance.
+ */
+ private long mNativeInstance;
+
+ long createNativeInstance() {
+ return 0;
+ }
+
+ void discardNativeInstance() {
+ if (mNativeInstance != 0) {
+ nSafeUnref(mNativeInstance);
+ mNativeInstance = 0;
+ }
+ }
@Override
protected void finalize() throws Throwable {
try {
- super.finalize();
+ if (mNativeInstance != 0) {
+ nSafeUnref(mNativeInstance);
+ }
+ mNativeInstance = -1;
} finally {
- destroyFilter(native_instance);
- native_instance = 0;
+ super.finalize();
}
}
- static native void destroyFilter(long native_instance);
+ /** @hide */
+ public long getNativeInstance() {
+ if (mNativeInstance == -1) {
+ throw new IllegalStateException("attempting to use a finalized ColorFilter");
+ }
+
+ if (mNativeInstance == 0) {
+ mNativeInstance = createNativeInstance();
+ }
+ return mNativeInstance;
+
+ }
+
+ static native void nSafeUnref(long native_instance);
}
diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java
index 1b1849e..6299b2c 100644
--- a/graphics/java/android/graphics/ColorMatrix.java
+++ b/graphics/java/android/graphics/ColorMatrix.java
@@ -268,4 +268,21 @@
m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f;
m[10] = 1; m[11] = 1.772f; m[12] = 0;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ // if (obj == this) return true; -- NaN value would mean matrix != itself
+ if (!(obj instanceof ColorMatrix)) {
+ return false;
+ }
+
+ // we don't use Arrays.equals(), since that considers NaN == NaN
+ final float[] other = ((ColorMatrix) obj).mArray;
+ for (int i = 0; i < 20; i++) {
+ if (other[i] != mArray[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 291c8ff..61f6cc5 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -16,6 +16,9 @@
package android.graphics;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* A color filter that transforms colors through a 4x5 color matrix. This filter
* can be used to change the saturation of pixels, convert from YUV to RGB, etc.
@@ -32,9 +35,8 @@
* the filter, so changes made to the matrix after the filter
* is constructed will not be reflected in the filter.
*/
- public ColorMatrixColorFilter(ColorMatrix matrix) {
+ public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) {
mMatrix.set(matrix);
- update();
}
/**
@@ -44,84 +46,76 @@
* matrix. The first 20 entries of the array are copied into
* the filter. See ColorMatrix.
*/
- public ColorMatrixColorFilter(float[] array) {
+ public ColorMatrixColorFilter(@NonNull float[] array) {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
mMatrix.set(array);
- update();
}
/**
- * Returns the {@link ColorMatrix} used by this filter. The returned
- * value is never null. Modifying the returned matrix does not have
- * any effect until you call {@link #setColorMatrix(ColorMatrix)}.
+ * Copies the ColorMatrix from the filter into the passed ColorMatrix.
*
- * @see #setColorMatrix(ColorMatrix)
- *
- * @hide
+ * @param colorMatrix Set to the current value of the filter's ColorMatrix.
*/
- public ColorMatrix getColorMatrix() {
- return mMatrix;
+ public void getColorMatrix(ColorMatrix colorMatrix) {
+ colorMatrix.set(mMatrix);
}
/**
- * Specifies the color matrix used by this filter. If the specified
- * color matrix is null, this filter's color matrix will be reset to
- * the identity matrix.
+ * Copies the provided color matrix to be used by this filter.
+ *
+ * If the specified color matrix is null, this filter's color matrix will be reset to the
+ * identity matrix.
*
* @param matrix A {@link ColorMatrix} or null
*
- * @see #getColorMatrix()
- * @see android.graphics.ColorMatrix#reset()
- * @see #setColorMatrix(float[])
- *
- * @hide
+ * @see #getColorMatrix(ColorMatrix)
+ * @see #setColorMatrixArray(float[])
+ * @see ColorMatrix#reset()
*/
- public void setColorMatrix(ColorMatrix matrix) {
+ public void setColorMatrix(@Nullable ColorMatrix matrix) {
+ discardNativeInstance();
if (matrix == null) {
mMatrix.reset();
- } else if (matrix != mMatrix) {
+ } else {
mMatrix.set(matrix);
}
- update();
}
/**
- * Specifies the color matrix used by this filter. If the specified
- * color matrix is null, this filter's color matrix will be reset to
- * the identity matrix.
+ * Copies the provided color matrix to be used by this filter.
+ *
+ * If the specified color matrix is null, this filter's color matrix will be reset to the
+ * identity matrix.
*
* @param array Array of floats used to transform colors, treated as a 4x5
* matrix. The first 20 entries of the array are copied into
* the filter. See {@link ColorMatrix}.
*
- * @see #getColorMatrix()
- * @see android.graphics.ColorMatrix#reset()
+ * @see #getColorMatrix(ColorMatrix)
* @see #setColorMatrix(ColorMatrix)
+ * @see ColorMatrix#reset()
*
* @throws ArrayIndexOutOfBoundsException if the specified array's
* length is < 20
- *
- * @hide
*/
- public void setColorMatrix(float[] array) {
+ public void setColorMatrixArray(@Nullable float[] array) {
+ // called '...Array' so that passing null isn't ambiguous
+ discardNativeInstance();
if (array == null) {
mMatrix.reset();
} else {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
-
mMatrix.set(array);
}
- update();
}
- private void update() {
- final float[] colorMatrix = mMatrix.getArray();
- destroyFilter(native_instance);
- native_instance = nativeColorMatrixFilter(colorMatrix);
+ @Override
+ long createNativeInstance() {
+ return nativeColorMatrixFilter(mMatrix.getArray());
}
private static native long nativeColorMatrixFilter(float[] array);
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index ad78430..b0c145b 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -21,6 +21,8 @@
package android.graphics;
+import android.annotation.ColorInt;
+
/**
* A color filter that can be used to simulate simple lighting effects.
* A <code>LightingColorFilter</code> is defined by two parameters, one
@@ -37,7 +39,9 @@
* The result is pinned to the <code>[0..255]</code> range for each channel.
*/
public class LightingColorFilter extends ColorFilter {
+ @ColorInt
private int mMul;
+ @ColorInt
private int mAdd;
/**
@@ -45,10 +49,9 @@
* and then adds a second color. The alpha components of the mul and add
* arguments are ignored.
*/
- public LightingColorFilter(int mul, int add) {
+ public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
mMul = mul;
mAdd = add;
- update();
}
/**
@@ -56,9 +59,8 @@
* color filter is applied.
*
* @see #setColorMultiply(int)
- *
- * @hide
*/
+ @ColorInt
public int getColorMultiply() {
return mMul;
}
@@ -69,12 +71,12 @@
* The alpha channel of this color is ignored.
*
* @see #getColorMultiply()
- *
- * @hide
*/
- public void setColorMultiply(int mul) {
- mMul = mul;
- update();
+ public void setColorMultiply(@ColorInt int mul) {
+ if (mMul != mul) {
+ mMul = mul;
+ discardNativeInstance();
+ }
}
/**
@@ -82,9 +84,8 @@
* when the color filter is applied.
*
* @see #setColorAdd(int)
- *
- * @hide
*/
+ @ColorInt
public int getColorAdd() {
return mAdd;
}
@@ -95,17 +96,17 @@
* The alpha channel of this color is ignored.
*
* @see #getColorAdd()
- *
- * @hide
*/
- public void setColorAdd(int add) {
- mAdd = add;
- update();
+ public void setColorAdd(@ColorInt int add) {
+ if (mAdd != add) {
+ mAdd = add;
+ discardNativeInstance();
+ }
}
- private void update() {
- destroyFilter(native_instance);
- native_instance = native_CreateLightingFilter(mMul, mAdd);
+ @Override
+ long createNativeInstance() {
+ return native_CreateLightingFilter(mMul, mAdd);
}
private static native long native_CreateLightingFilter(int mul, int add);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7ca4615..5d6aa8a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -42,7 +42,8 @@
public class Paint {
private long mNativePaint;
- private long mNativeShader = 0;
+ private long mNativeShader;
+ private long mNativeColorFilter;
// The approximate size of a native paint object.
private static final long NATIVE_PAINT_SIZE = 98;
@@ -584,6 +585,11 @@
mNativeShader = newNativeShader;
nSetShader(mNativePaint, mNativeShader);
}
+ long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance();
+ if (newNativeColorFilter != mNativeColorFilter) {
+ mNativeColorFilter = newNativeColorFilter;
+ nSetColorFilter(mNativePaint, mNativeColorFilter);
+ }
return mNativePaint;
}
@@ -1044,10 +1050,13 @@
* @return filter
*/
public ColorFilter setColorFilter(ColorFilter filter) {
- long filterNative = 0;
- if (filter != null)
- filterNative = filter.native_instance;
- nSetColorFilter(mNativePaint, filterNative);
+ // If mColorFilter changes, cached value of native shader aren't valid, since
+ // old shader's pointer may be reused by another shader allocation later
+ if (mColorFilter != filter) {
+ mNativeColorFilter = -1;
+ }
+
+ // Defer setting the filter natively until getNativeInstance() is called
mColorFilter = filter;
return filter;
}
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 69d6891..ccc6ead 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -24,6 +24,7 @@
* color and a specific {@link PorterDuff Porter-Duff composite mode}.
*/
public class PorterDuffColorFilter extends ColorFilter {
+ @ColorInt
private int mColor;
private PorterDuff.Mode mMode;
@@ -40,7 +41,6 @@
public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
mColor = color;
mMode = mode;
- update();
}
/**
@@ -49,9 +49,8 @@
*
* @see Color
* @see #setColor(int)
- *
- * @hide
*/
+ @ColorInt
public int getColor() {
return mColor;
}
@@ -65,12 +64,12 @@
* @see Color
* @see #getColor()
* @see #getMode()
- *
- * @hide
*/
- public void setColor(int color) {
- mColor = color;
- update();
+ public void setColor(@ColorInt int color) {
+ if (mColor != color) {
+ mColor = color;
+ discardNativeInstance();
+ }
}
/**
@@ -79,8 +78,6 @@
*
* @see PorterDuff
* @see #setMode(android.graphics.PorterDuff.Mode)
- *
- * @hide
*/
public PorterDuff.Mode getMode() {
return mMode;
@@ -93,17 +90,18 @@
* @see PorterDuff
* @see #getMode()
* @see #getColor()
- *
- * @hide
*/
public void setMode(@NonNull PorterDuff.Mode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode must be non-null");
+ }
mMode = mode;
- update();
+ discardNativeInstance();
}
- private void update() {
- destroyFilter(native_instance);
- native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
+ @Override
+ long createNativeInstance() {
+ return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
}
@Override
@@ -115,10 +113,7 @@
return false;
}
final PorterDuffColorFilter other = (PorterDuffColorFilter) object;
- if (mColor != other.mColor || mMode != other.mMode) {
- return false;
- }
- return true;
+ return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt);
}
@Override
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index b584e0d..8410ab2 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -106,8 +106,10 @@
}
void discardNativeInstance() {
- nativeSafeUnref(mNativeInstance);
- mNativeInstance = 0;
+ if (mNativeInstance != 0) {
+ nativeSafeUnref(mNativeInstance);
+ mNativeInstance = 0;
+ }
}
/**
@@ -120,7 +122,9 @@
@Override
protected void finalize() throws Throwable {
try {
- nativeSafeUnref(mNativeInstance);
+ if (mNativeInstance != 0) {
+ nativeSafeUnref(mNativeInstance);
+ }
mNativeInstance = -1;
} finally {
super.finalize();
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 0722c18..c6c9271 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -218,6 +218,8 @@
}
/**
+ * Only call this method after bound is set on this drawable.
+ *
* @return the mask path object used to clip the drawable
*/
public Path getIconMask() {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3a12419..a1539b8 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -333,7 +333,7 @@
// Color filters always override tint filters.
final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
final long colorFilterNativeInstance = colorFilter == null ? 0 :
- colorFilter.native_instance;
+ colorFilter.getNativeInstance();
boolean canReuseCache = mVectorState.canReuseCache();
int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
colorFilterNativeInstance, mTmpBounds, needMirroring(),
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index d8afa35..a738ba4 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -38,13 +38,14 @@
}
// "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a linear color. The color
- // is not pre-multiplied.
- void setUnPreMultipliedSRGB(uint32_t color) {
+ // After calling this method, the color is stored as a un-premultiplied linear color
+ // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied
+ // gamma-encoded sRGB color
+ void setUnPreMultiplied(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
- r = EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
- g = EOCF_sRGB(((color >> 8) & 0xff) / 255.0f);
- b = EOCF_sRGB(((color ) & 0xff) / 255.0f);
+ r = EOCF(((color >> 16) & 0xff) / 255.0f);
+ g = EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = EOCF(((color ) & 0xff) / 255.0f);
}
bool isNotBlack() {
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 18bfcc2..dceb285 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -189,9 +189,9 @@
float amount, uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
- *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f);
- *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f);
- *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f);
*dst++ = uint8_t(a * 255.0f);
}
@@ -201,17 +201,14 @@
float a = start.a * oppAmount + end.a * amount;
float* d = (float*) dst;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ // We want to stay linear
*d++ = a * (start.r * oppAmount + end.r * amount);
*d++ = a * (start.g * oppAmount + end.g * amount);
*d++ = a * (start.b * oppAmount + end.b * amount);
#else
- // What we're doing to the alpha channel here is technically incorrect
- // but reproduces Android's old behavior when the alpha was pre-multiplied
- // with gamma-encoded colors
- a = EOCF_sRGB(a);
- *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
- *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
- *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
+ *d++ = a * OECF(start.r * oppAmount + end.r * amount);
+ *d++ = a * OECF(start.g * oppAmount + end.g * amount);
+ *d++ = a * OECF(start.b * oppAmount + end.b * amount);
#endif
*d++ = a;
dst += 4 * sizeof(float);
@@ -232,10 +229,10 @@
ChannelMixer mix = gMixers[mUseFloatTexture];
FloatColor start;
- start.setUnPreMultipliedSRGB(colors[0]);
+ start.setUnPreMultiplied(colors[0]);
FloatColor end;
- end.setUnPreMultipliedSRGB(colors[1]);
+ end.setUnPreMultiplied(colors[1]);
int currentPos = 1;
float startPos = positions[0];
@@ -250,7 +247,7 @@
currentPos++;
- end.setUnPreMultipliedSRGB(colors[currentPos]);
+ end.setUnPreMultiplied(colors[currentPos]);
distance = positions[currentPos] - startPos;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 3f842e0..38c23e4 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -202,23 +202,26 @@
)__SHADER__";
const char* gFS_Gradient_Preamble[2] = {
// Linear framebuffer
- "\nvec4 dither(const vec4 color) {\n"
- " return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n"
- "}\n"
- "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
- " vec4 c = mix(a, b, v);\n"
- " c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility
- " return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n"
- "}\n",
+ R"__SHADER__(
+ vec4 dither(const vec4 color) {
+ return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+ }
+ vec4 gradientMix(const vec4 a, const vec4 b, float v) {
+ vec4 c = mix(a, b, v);
+ return vec4(c.rgb * c.a, c.a);
+ }
+ )__SHADER__",
// sRGB framebuffer
- "\nvec4 dither(const vec4 color) {\n"
- " vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n"
- " return vec4(dithered * dithered, color.a);\n"
- "}\n"
- "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
- " vec4 c = mix(a, b, v);\n"
- " return vec4(c.rgb * c.a, c.a);\n"
- "}\n"
+ R"__SHADER__(
+ vec4 dither(const vec4 color) {
+ vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+ return vec4(dithered * dithered, color.a);
+ }
+ vec4 gradientMixMix(const vec4 a, const vec4 b, float v) {
+ vec4 c = mix(a, b, v);
+ return vec4(c.rgb * c.a, c.a);
+ }
+ )__SHADER__",
};
// Uses luminance coefficients from Rec.709 to choose the appropriate gamma
@@ -272,19 +275,19 @@
// Linear
" vec4 gradientColor = texture2D(gradientSampler, linear);\n",
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
// Circular
" vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
// Sweep
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 760c10c..4f7f9d7 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,8 +173,8 @@
outData->gradientSampler = 0;
outData->gradientTexture = nullptr;
- outData->startColor.setUnPreMultipliedSRGB(gradInfo.fColors[0]);
- outData->endColor.setUnPreMultipliedSRGB(gradInfo.fColors[1]);
+ outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]);
+ outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]);
}
return true;
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
index 537b3ea..ef4784b 100644
--- a/libs/hwui/VkLayer.cpp
+++ b/libs/hwui/VkLayer.cpp
@@ -29,7 +29,7 @@
SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
surface->getCanvas()->clear(SK_ColorBLUE);
- mImage = surface->makeImageSnapshot(SkBudgeted::kNo);
+ mImage = surface->makeImageSnapshot();
}
void VkLayer::onVkContextDestroyed() {
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
index 2b75c36..696e9b1 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
@@ -17,6 +17,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+ <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
<item android:color="@android:color/transparent" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
index f296076..6415ecb4 100644
--- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -17,14 +17,15 @@
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
<group
android:scaleX="1.2"
android:scaleY="1.2"
android:pivotX="12.0"
android:pivotY="12.0">
<path
- android:fillColor="@color/qs_user_detail_icon_muted"
+ android:fillColor="#FFFFFFFF"
android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 8d1f9e4..9d1fb8f 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -14,24 +14,39 @@
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:layout_width="match_parent"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:paddingTop="8dp">
+ <LinearLayout
+ android:id="@+id/label_group"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
- <TextView android:id="@+id/tile_label"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/tile_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorPrimary"
- android:gravity="center_horizontal"
- android:minLines="2"
+ android:clickable="false"
+ android:maxLines="2"
android:padding="0dp"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:clickable="false" />
- <ImageView android:id="@+id/restricted_padlock"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <ImageView
+ android:id="@+id/expand_indicator"
+ android:layout_marginStart="4dp"
+ android:layout_width="12dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/qs_dual_tile_caret"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <ImageView android:id="@+id/restricted_padlock"
android:layout_width="@dimen/qs_tile_text_size"
android:layout_height="match_parent"
android:paddingBottom="@dimen/qs_tile_text_size"
@@ -39,4 +54,32 @@
android:layout_marginLeft="@dimen/restricted_padlock_pading"
android:scaleType="centerInside"
android:visibility="gone" />
-</LinearLayout>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/app_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@id/label_group"
+ android:layout_alignEnd="@id/label_group"
+ android:layout_below="@id/label_group"
+ android:clickable="false"
+ android:maxLines="1"
+ android:padding="0dp"
+ android:visibility="gone"
+ android:gravity="center"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <View
+ android:id="@+id/underline"
+ android:layout_width="30dp"
+ android:layout_height="1dp"
+ android:layout_marginTop="2dp"
+ android:layout_alignStart="@id/label_group"
+ android:layout_alignEnd="@id/label_group"
+ android:layout_below="@id/label_group"
+ android:alpha="?android:attr/disabledAlpha"
+ android:background="?android:attr/colorForeground"/>
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 8c6c7cf..c7bfaef 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -53,7 +53,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/qs_detail_item_secondary_text_size"
- android:textColor="@color/qs_user_detail_name"
+ android:textColor="?android:attr/textColorSecondary"
android:gravity="center_horizontal" />
<ImageView
android:id="@+id/restricted_padlock"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 0629d66..b080642 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -35,19 +35,13 @@
protected void createLabel() {
super.createLabel();
mLabelMinLines = mLabel.getMinLines();
- View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
- mAppLabel = (TextView) view.findViewById(R.id.tile_label);
+ mAppLabel = findViewById(R.id.app_label);
mAppLabel.setAlpha(.6f);
- mAppLabel.setSingleLine(true);
- addView(view);
}
public void setShowAppLabel(boolean showAppLabel) {
mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
mLabel.setSingleLine(showAppLabel);
- if (!showAppLabel) {
- mLabel.setMinLines(mLabelMinLines);
- }
}
public void setAppLabel(CharSequence label) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 198cb9e..d8e5542 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -228,6 +228,7 @@
}
private final Callback mKeyguardCallback = () -> {
+ if (!isAttachedToWindow()) return;
if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
hide(0, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 547bef7..2ac592f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -165,6 +165,7 @@
}
TileInfo info = new TileInfo();
info.state = state;
+ info.state.dualTarget = false; // No dual targets in edit.
info.state.expandedAccessibilityClassName =
Button.class.getName();
info.spec = spec;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 5ac7891..948954c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -369,7 +369,6 @@
Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
intent, 0);
} else {
- mAnnounceNextStateChange = true;
handleClick();
}
} else if (msg.what == SECONDARY_CLICK) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 2c04e82..d2ae6e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -36,11 +36,12 @@
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
- private final View mDivider;
+ private View mDivider;
protected TextView mLabel;
private ImageView mPadLock;
private int mState;
private ViewGroup mLabelContainer;
+ private View mExpandIndicator;
public QSTileView(Context context, QSIconView icon) {
this(context, icon, false);
@@ -54,8 +55,6 @@
setClickable(true);
setId(View.generateViewId());
- mDivider = LayoutInflater.from(context).inflate(R.layout.divider, this, false);
- addView(mDivider);
createLabel();
setOrientation(VERTICAL);
setGravity(Gravity.CENTER);
@@ -81,8 +80,10 @@
.inflate(R.layout.qs_tile_label, this, false);
mLabelContainer.setClipChildren(false);
mLabelContainer.setClipToPadding(false);
- mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label);
- mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock);
+ mLabel = mLabelContainer.findViewById(R.id.tile_label);
+ mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock);
+ mDivider = mLabelContainer.findViewById(R.id.underline);
+ mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator);
addView(mLabelContainer);
}
@@ -101,6 +102,7 @@
mLabel.setText(state.label);
}
mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE);
+ mExpandIndicator.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE);
if (state.dualTarget != mLabelContainer.isClickable()) {
mLabelContainer.setClickable(state.dualTarget);
mLabelContainer.setLongClickable(state.dualTarget);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 47468ae..ac24e2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -67,6 +67,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.LauncherIcons;
import android.util.Log;
import android.util.MutableBoolean;
import android.view.Display;
@@ -142,6 +143,7 @@
int mDummyThumbnailHeight;
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
+ LauncherIcons mLauncherIcons;
private final Handler mHandler = new H();
@@ -299,6 +301,7 @@
Collections.addAll(sRecentsBlacklist,
res.getStringArray(R.array.recents_blacklist_array));
}
+ mLauncherIcons = new LauncherIcons(context);
}
/**
@@ -834,7 +837,7 @@
return new ColorDrawable(0xFF666666);
}
- Drawable icon = info.loadIcon(mPm);
+ Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm));
return getBadgedIcon(icon, userId);
}
@@ -850,7 +853,7 @@
return new ColorDrawable(0xFF666666);
}
- Drawable icon = appInfo.loadIcon(mPm);
+ Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm));
return getBadgedIcon(icon, userId);
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 10ff8ad..ddd8d7b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -47,7 +47,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
metrics-helper-lib \
android-support-test \
- mockito-updated-target-minus-junit4 \
+ mockito-target-minus-junit4 \
SystemUI-proto \
SystemUI-tags \
legacy-android-test \
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 58e020f..8a3b9af 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -56,6 +56,12 @@
// Type for APP_TRANSITION event: The transition brought an already existing activity to the
// front.
TYPE_TRANSITION_HOT_LAUNCH = 9;
+
+ // The action was successful
+ TYPE_SUCCESS = 10;
+
+ // The action failed
+ TYPE_FAILURE = 11;
}
// Known visual elements: views or controls.
@@ -3672,6 +3678,105 @@
// PACKAGE: The package name of the app the permission was revoked for
ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
+ // ACTION: Phase 1 of instant application resolution occurred
+ // OS: O
+ ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE = 899;
+
+ // ACTION: Phase 2 of instant application resolution occurred
+ // OS: O
+ ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO = 900;
+
+ // FIELD: The amount of time for an ephemeral resolution phase; in milliseconds
+ // OS: O
+ FIELD_INSTANT_APP_RESOLUTION_DELAY_MS = 901;
+
+ // FIELD: The status of an ephemeral resolution phase
+ // Value 0: success
+ // Value 1: no full hash match
+ // OS: O
+ FIELD_INSTANT_APP_RESOLUTION_STATUS = 902;
+
+ // FIELD - A token to identify all events that are part of the same instant application launch
+ // OS: O
+ FIELD_INSTANT_APP_LAUNCH_TOKEN = 903;
+
+ // FIELD - The name of the package responsible for launching the activity
+ // OS: O
+ APP_TRANSITION_CALLING_PACKAGE_NAME = 904;
+
+ // FIELD - Whether or not the launched activity is part of an instant application
+ // OS: O
+ APP_TRANSITION_IS_EPHEMERAL = 905;
+
+ // An autofill session was started
+ // Package: Package of app that is autofilled
+ AUTOFILL_SESSION_STARTED = 906;
+
+ // An autofill request was processed by a service
+ // Type TYPE_SUCCESS: The request succeeded
+ // Type TYPE_FAILURE: The request failed
+ // Package: Package of app that is autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case)
+ AUTOFILL_REQUEST = 907;
+
+ // Tag of a field for a package of an autofill service
+ FIELD_AUTOFILL_SERVICE = 908;
+
+ // Tag of a field for the number of datasets
+ FIELD_AUTOFILL_NUM_DATASETS = 909;
+
+ // An autofill dataset selection UI was shown
+ // Type TYPE_DISMISS: UI was explicityly canceled by the user
+ // Type TYPE_CLOSE: UI was destroyed without influence of the user
+ // Type TYPE_ACTION: dataset was selected
+ // Type TYPE_DETAIL: authentication was selected
+ // Package: Package of app that was autofilled
+ // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text
+ // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
+ AUTOFILL_FILL_UI = 910;
+
+ // Tag of a field for the length of the filter text
+ FIELD_AUTOFILL_FILTERTEXT_LEN = 911;
+
+ // An autofill authentification succeeded
+ // Package: Package of app that was autofilled
+ AUTOFILL_AUTHENTICATED = 912;
+
+ // An activity was autofilled and all values could be applied
+ // Package: Package of app that is autofilled
+ // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
+ // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
+ AUTOFILL_DATASET_APPLIED = 913;
+
+ // Tag of a field for the number values to be filled in
+ FIELD_AUTOFILL_NUM_VALUES = 914;
+
+ // Tag of a field for the number of views that were filled
+ FIELD_AUTOFILL_NUM_VIEWS_FILLED = 915;
+
+ // An autofill save UI was shown
+ // Type TYPE_DISMISS: UI was explicityly canceled by the user
+ // Type TYPE_CLOSE: UI was destroyed without influence of the user
+ // Type TYPE_ACTION: data was saved
+ // Package: Package of app that was autofilled
+ // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved
+ AUTOFILL_SAVE_UI = 916;
+
+ // Tag of a field for the number of saveable ids
+ FIELD_AUTOFILL_NUM_IDS = 917;
+
+ // ACTION: An autofill service was reqiested to save data
+ // Type TYPE_SUCCESS: The request succeeded
+ // Type TYPE_FAILURE: The request failed
+ // Package: Package of app that was autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ AUTOFILL_DATA_SAVE_REQUEST = 918;
+
+ // An auto-fill session was finished
+ // Package: Package of app that was autofilled
+ AUTOFILL_SESSION_FINISHED = 919;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index af1193d..c7ba1ff 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.graphics.Rect;
@@ -53,6 +54,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -316,13 +318,27 @@
@Override
public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
- boolean hasCallback, int flags) {
+ boolean hasCallback, int flags, String packageName) {
// TODO(b/33197203): make sure it's called by resumed / focused activity
+ activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
+ appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
+ autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
+ bounds = Preconditions.checkNotNull(bounds, "bounds");
+ packageName = Preconditions.checkNotNull(packageName, "packageName");
+
+ Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
+
+ try {
+ mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException(packageName + " is not a valid package", e);
+ }
+
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
service.startSessionLocked(activityToken, windowToken, appCallback,
- autofillId, bounds, value, hasCallback, flags);
+ autofillId, bounds, value, hasCallback, flags, packageName);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 3e5ad82..df76009 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -28,6 +28,7 @@
import static com.android.server.autofill.Helper.VERBOSE;
import static com.android.server.autofill.Helper.findValue;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -43,6 +44,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
+import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -67,7 +69,11 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
+import android.view.autofill.AutofillManager.AutofillCallback;
+
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.AutoFillUI;
@@ -92,6 +98,7 @@
private final Context mContext;
private final Object mLock;
private final AutoFillUI mUi;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
private RemoteCallbackList<IAutoFillManagerClient> mClients;
private AutofillServiceInfo mInfo;
@@ -228,9 +235,8 @@
if (!hasService()) {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
- Session session = mSessions.valueAt(i);
- session.destroyLocked();
- mSessions.removeAt(i);
+ final Session session = mSessions.valueAt(i);
+ session.removeSelfLocked();
}
}
sendStateToClients();
@@ -284,9 +290,10 @@
}
}
- void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken,
- AutofillId autofillId, Rect bounds, AutofillValue value, boolean hasCallback,
- int flags) {
+ void startSessionLocked(@NonNull IBinder activityToken, @Nullable IBinder windowToken,
+ @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds,
+ @Nullable AutofillValue value, boolean hasCallback, int flags,
+ @NonNull String packageName) {
if (!hasService()) {
return;
}
@@ -305,7 +312,7 @@
}
final Session newSession = createSessionByTokenLocked(activityToken,
- windowToken, appCallbackToken, hasCallback, flags);
+ windowToken, appCallbackToken, hasCallback, flags, packageName);
newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION);
}
@@ -320,7 +327,13 @@
return;
}
- session.showSaveLocked();
+ final boolean finished = session.showSaveLocked();
+ if (DEBUG) {
+ Log.d(TAG, "finishSessionLocked(): session finished on save? " + finished);
+ }
+ if (finished) {
+ session.removeSelf();
+ }
}
void cancelSessionLocked(IBinder activityToken) {
@@ -333,14 +346,14 @@
Slog.w(TAG, "cancelSessionLocked(): no session for " + activityToken);
return;
}
-
- session.destroyLocked();
+ session.removeSelfLocked();
}
- private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
- IBinder appCallbackToken, boolean hasCallback, int flags) {
+ private Session createSessionByTokenLocked(@NonNull IBinder activityToken,
+ @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback,
+ int flags, @NonNull String packageName) {
final Session newSession = new Session(mContext, activityToken,
- windowToken, appCallbackToken, hasCallback, flags);
+ windowToken, appCallbackToken, hasCallback, flags, packageName);
mSessions.put(activityToken, newSession);
/*
@@ -351,7 +364,6 @@
* - display disclosure if needed
*/
try {
- // TODO(b/33197203): add MetricsLogger call
final Bundle receiverExtras = new Bundle();
receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken);
final long identity = Binder.clearCallingIdentity();
@@ -371,7 +383,6 @@
void updateSessionLocked(IBinder activityToken, AutofillId autofillId, Rect bounds,
AutofillValue value, int flags) {
- // TODO(b/33197203): add MetricsLogger call
final Session session = mSessions.get(activityToken);
if (session == null) {
if (VERBOSE) {
@@ -595,6 +606,9 @@
private final IBinder mActivityToken;
private final IBinder mWindowToken;
+ /** Package name of the app that is auto-filled */
+ @NonNull private final String mPackageName;
+
@GuardedBy("mLock")
private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -634,15 +648,16 @@
* Flags used to start the session.
*/
private int mFlags;
-
- private Session(Context context, IBinder activityToken, IBinder windowToken,
- IBinder client, boolean hasCallback, int flags) {
+ private Session(@NonNull Context context, @NonNull IBinder activityToken,
+ @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
+ int flags, @NonNull String packageName) {
mRemoteFillService = new RemoteFillService(context,
mInfo.getServiceInfo().getComponentName(), mUserId, this);
mActivityToken = activityToken;
mWindowToken = windowToken;
mHasCallback = hasCallback;
mFlags = flags;
+ mPackageName = packageName;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
try {
@@ -656,41 +671,82 @@
} catch (RemoteException e) {
Slog.w(TAG, "linkToDeath() on mClient failed: " + e);
}
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
}
// FillServiceCallbacks
@Override
- public void onFillRequestSuccess(FillResponse response) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onFillRequestSuccess(@Nullable FillResponse response,
+ @NonNull String servicePackageName) {
if (response == null) {
+ // Nothing to be done, but need to notify client.
+ notifyUnavailableToClient();
removeSelf();
return;
}
+
+ if ((response.getDatasets() == null || response.getDatasets().isEmpty())
+ && response.getAuthentication() == null) {
+ // Response is "empty" from an UI point of view, need to notify client.
+ notifyUnavailableToClient();
+ }
synchronized (mLock) {
processResponseLocked(response);
}
+
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+ response.getDatasets() == null ? 0 : response.getDatasets().size())
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
}
// FillServiceCallbacks
@Override
- public void onFillRequestFailure(CharSequence message) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onFillRequestFailure(@Nullable CharSequence message,
+ @NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
getUiForShowing().showError(message);
removeSelf();
}
// FillServiceCallbacks
@Override
- public void onSaveRequestSuccess() {
- // TODO(b/33197203): add MetricsLogger call
+ public void onSaveRequestSuccess(@NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(
+ MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
// Nothing left to do...
removeSelf();
}
// FillServiceCallbacks
@Override
- public void onSaveRequestFailure(CharSequence message) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onSaveRequestFailure(@Nullable CharSequence message,
+ @NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(
+ MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
getUiForShowing().showError(message);
removeSelf();
}
@@ -702,9 +758,7 @@
synchronized (mLock) {
fillInIntent = createAuthFillInIntent(mStructure);
}
- mHandlerCaller.getHandler().post(() -> {
- startAuthentication(intent, fillInIntent);
- });
+ mHandlerCaller.getHandler().post(() -> startAuthentication(intent, fillInIntent));
}
// FillServiceCallbacks
@@ -724,8 +778,7 @@
Binder.restoreCallingIdentity(identity);
}
synchronized (mLock) {
- destroyLocked();
- mSessions.remove(this);
+ removeSelfLocked();
}
}
@@ -738,9 +791,7 @@
// AutoFillUiCallback
@Override
public void fill(Dataset dataset) {
- mHandlerCaller.getHandler().post(() -> {
- autoFill(dataset);
- });
+ mHandlerCaller.getHandler().post(() -> autoFill(dataset));
}
// AutoFillUiCallback
@@ -753,17 +804,13 @@
// AutoFillUiCallback
@Override
public void cancelSave() {
- mHandlerCaller.getHandler().post(() -> {
- removeSelf();
- });
+ mHandlerCaller.getHandler().post(() -> removeSelf());
}
// AutoFillUiCallback
@Override
public void onEvent(AutofillId id, int event) {
- mHandlerCaller.getHandler().post(() -> {
- notifyChangeToClient(id, event);
- });
+ mHandlerCaller.getHandler().post(() -> notifyChangeToClient(id, event));
}
public void setAuthenticationResultLocked(Bundle data) {
@@ -773,6 +820,9 @@
Parcelable result = data.getParcelable(
AutofillManager.EXTRA_AUTHENTICATION_RESULT);
if (result instanceof FillResponse) {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_AUTHENTICATED,
+ mPackageName);
+
mCurrentResponse = (FillResponse) result;
processResponseLocked(mCurrentResponse);
} else if (result instanceof Dataset) {
@@ -790,12 +840,14 @@
}
/**
- * Show the save UI, when session can be saved.
+ * Shows the save UI, when session can be saved.
+ *
+ * @return {@code true} if session is done, or {@code false} if it's pending user action.
*/
- public void showSaveLocked() {
+ public boolean showSaveLocked() {
if (mStructure == null) {
Slog.wtf(TAG, "showSaveLocked(): no mStructure");
- return;
+ return true;
}
if (mCurrentResponse == null) {
// Happens when the activity / session was finished before the service replied, or
@@ -803,7 +855,7 @@
if (DEBUG) {
Slog.d(TAG, "showSaveLocked(): no mCurrentResponse");
}
- return;
+ return true;
}
final SaveInfo saveInfo = mCurrentResponse.getSaveInfo();
if (DEBUG) {
@@ -819,13 +871,13 @@
*/
if (saveInfo == null) {
- return;
+ return true;
}
final AutofillId[] requiredIds = saveInfo.getRequiredIds();
if (requiredIds == null || requiredIds.length == 0) {
Slog.w(TAG, "showSaveLocked(): no required ids on saveInfo");
- return;
+ return true;
}
boolean allRequiredAreNotEmpty = true;
@@ -894,8 +946,8 @@
if (atLeastOneChanged) {
getUiForShowing().showSaveUi(
mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
- saveInfo);
- return;
+ saveInfo, mPackageName);
+ return false;
}
}
// Nothing changed...
@@ -904,7 +956,7 @@
+ "allRequiredAreNotNull=" + allRequiredAreNotEmpty
+ ", atLeastOneChanged=" + atLeastOneChanged);
}
- removeSelf();
+ return true;
}
/**
@@ -946,7 +998,7 @@
mStructure.dump();
}
- mRemoteFillService.onSaveRequest(mStructure, extras);
+ mRemoteFillService.onSaveRequest(mStructure, extras, () -> removeSelf());
}
void updateLocked(AutofillId id, Rect bounds, AutofillValue value, int flags) {
@@ -1034,7 +1086,7 @@
filterText = value.getTextValue().toString();
}
- getUiForShowing().showFillUi(filledId, response, bounds, filterText);
+ getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName);
}
private void notifyChangeToClient(AutofillId id, int event) {
@@ -1046,17 +1098,24 @@
}
}
+ private void notifyUnavailableToClient() {
+ if (mCurrentViewState == null) {
+ // TODO(b/33197203): temporary sanity check; should never happen
+ Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null");
+ return;
+ }
+ notifyChangeToClient(mCurrentViewState.mId, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
+
private void processResponseLocked(FillResponse response) {
if (DEBUG) {
Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication()
+ "):" + response);
}
- // TODO(b/33197203): add MetricsLogger calls
-
if (mCurrentViewState == null) {
// TODO(b/33197203): temporary sanity check; should never happen
- Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null");
+ Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null");
return;
}
@@ -1188,17 +1247,23 @@
private void destroyLocked() {
mRemoteFillService.destroy();
mUi.setCallback(null, null);
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED,
+ mPackageName);
}
- private void removeSelf() {
- if (VERBOSE) {
- Slog.v(TAG, "removeSelf()");
- }
-
+ void removeSelf() {
synchronized (mLock) {
- destroyLocked();
- mSessions.remove(mActivityToken);
+ removeSelfLocked();
}
}
+
+ private void removeSelfLocked() {
+ if (VERBOSE) {
+ Slog.v(TAG, "removeSelfLocked()");
+ }
+ destroyLocked();
+ mSessions.remove(mActivityToken);
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index b1cc89b..d1c8b4f8 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -16,6 +16,8 @@
package com.android.server.autofill;
+import static com.android.server.autofill.Helper.DEBUG;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.assist.AssistStructure;
@@ -38,8 +40,10 @@
import android.service.autofill.ISaveCallback;
import android.text.format.DateUtils;
import android.util.Slog;
+
import com.android.internal.os.HandlerCaller;
import com.android.server.FgThread;
+import com.android.server.autofill.AutofillManagerServiceImpl.Session;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -55,8 +59,6 @@
final class RemoteFillService implements DeathRecipient {
private static final String LOG_TAG = "RemoteFillService";
- private static final boolean DEBUG = Helper.DEBUG;
-
// How long after the last interaction with the service we would unbind
private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
@@ -87,10 +89,10 @@
private PendingRequest mPendingRequest;
public interface FillServiceCallbacks {
- void onFillRequestSuccess(FillResponse response);
- void onFillRequestFailure(CharSequence message);
- void onSaveRequestSuccess();
- void onSaveRequestFailure(CharSequence message);
+ void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName);
+ void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
+ void onSaveRequestSuccess(@NonNull String servicePackageName);
+ void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
void onServiceDied(RemoteFillService service);
void onDisableSelf();
}
@@ -139,9 +141,10 @@
mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
}
- public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) {
+ public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+ @Nullable Runnable finalizer) {
cancelScheduledUnbind();
- final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this);
+ final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this, finalizer);
mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget();
}
@@ -262,7 +265,7 @@
FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response);
+ mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
}
});
}
@@ -271,7 +274,7 @@
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestFailure(message);
+ mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
}
});
}
@@ -279,7 +282,7 @@
private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestSuccess();
+ mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
}
});
}
@@ -288,7 +291,7 @@
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestFailure(message);
+ mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
}
});
}
@@ -414,8 +417,8 @@
private static final class PendingFillRequest extends PendingRequest {
private final Object mLock = new Object();
private final WeakReference<RemoteFillService> mWeakService;
- private AssistStructure mStructure;
- private Bundle mExtras;
+ private final AssistStructure mStructure;
+ private final Bundle mExtras;
private final IFillCallback mCallback;
private ICancellationSignal mCancellation;
private boolean mCancelled;
@@ -473,10 +476,6 @@
try {
remoteService.mAutoFillService.onFillRequest(mStructure,
mExtras, mCallback, mFlags);
- synchronized (mLock) {
- mStructure = null;
- mExtras = null;
- }
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on fill request", e);
cancel();
@@ -506,17 +505,18 @@
}
private static final class PendingSaveRequest extends PendingRequest {
- private final Object mLock = new Object();
private final WeakReference<RemoteFillService> mWeakService;
- private AssistStructure mStructure;
- private Bundle mExtras;
+ private final AssistStructure mStructure;
+ private final Bundle mExtras;
private final ISaveCallback mCallback;
+ private final Runnable mFinalizer;
- public PendingSaveRequest(@NonNull AssistStructure structure,
- @Nullable Bundle extras, @NonNull RemoteFillService service) {
+ public PendingSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras,
+ @NonNull RemoteFillService service, @Nullable Runnable finalizer) {
mStructure = structure;
mExtras = extras;
mWeakService = new WeakReference<>(service);
+ mFinalizer = finalizer;
mCallback = new ISaveCallback.Stub() {
@Override
public void onSuccess() {
@@ -540,19 +540,17 @@
@Override
public void run() {
- RemoteFillService service = mWeakService.get();
+ final RemoteFillService service = mWeakService.get();
if (service != null) {
try {
- service.mAutoFillService.onSaveRequest(mStructure,
- mExtras, mCallback);
- synchronized (mLock) {
- mStructure = null;
- mExtras = null;
- }
+ service.mAutoFillService.onSaveRequest(mStructure, mExtras, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on save request", e);
}
}
+ if (mFinalizer != null) {
+ mFinalizer.run();
+ }
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index c7e59a3..776fa1e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.IntentSender;
import android.graphics.Rect;
+import android.metrics.LogMaker;
import android.os.Handler;
import android.os.IBinder;
import android.service.autofill.Dataset;
@@ -34,6 +35,8 @@
import android.view.autofill.AutofillId;
import android.widget.Toast;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -60,6 +63,7 @@
private @Nullable IBinder mWindowToken;
private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS);
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
public interface AutoFillUiCallback {
void authenticate(@NonNull IntentSender intent);
@@ -152,9 +156,17 @@
* @param response the current fill response
* @param anchorBounds bounds of the focused view
* @param filterText text of the view to be filled
+ * @param packageName package name of the activity that is filled
*/
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
- @NonNull Rect anchorBounds, @Nullable String filterText) {
+ @NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) {
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
+ .setPackageName(packageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
+ filterText == null ? 0 : filterText.length())
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+ response.getDatasets() == null ? 0 : response.getDatasets().size());
+
mHandler.post(() -> {
if (!hasCallback()) {
return;
@@ -164,6 +176,7 @@
mWindowToken, anchorBounds, filterText, new FillUi.Callback() {
@Override
public void onResponsePicked(FillResponse response) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
hideFillUiUiThread();
if (mCallback != null) {
mCallback.authenticate(response.getAuthentication());
@@ -172,17 +185,25 @@
@Override
public void onDatasetPicked(Dataset dataset) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
hideFillUiUiThread();
if (mCallback != null) {
mCallback.fill(dataset);
}
- // TODO(b/33197203): add MetricsLogger call
}
@Override
public void onCanceled() {
+ log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
hideFillUiUiThread();
- // TODO(b/33197203): add MetricsLogger call
+ }
+
+ @Override
+ public void onDestroy() {
+ if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ }
+ mMetricsLogger.write(log);
}
});
mCallback.onEvent(focusedId, EVENT_INPUT_SHOWN);
@@ -192,7 +213,16 @@
/**
* Shows the UI asking the user to save for autofill.
*/
- public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) {
+ public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
+ @NonNull String packageName) {
+ int numIds = 0;
+ numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
+ numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
+
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI))
+ .setPackageName(packageName).addTaggedData(
+ MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
+
mHandler.post(() -> {
if (!hasCallback()) {
return;
@@ -202,16 +232,16 @@
new SaveUi.OnSaveListener() {
@Override
public void onSave() {
+ log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
hideSaveUiUiThread();
if (mCallback != null) {
mCallback.save();
}
- // TODO(b/33197203): add MetricsLogger call
}
@Override
public void onCancel(IntentSender listener) {
- // TODO(b/33197203): add MetricsLogger call
+ log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
hideSaveUiUiThread();
if (listener != null) {
try {
@@ -225,6 +255,14 @@
mCallback.cancelSave();
}
}
+
+ @Override
+ public void onDestroy() {
+ if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ }
+ mMetricsLogger.write(log);
+ }
}, mSaveTimeoutMs);
});
}
@@ -247,11 +285,17 @@
}
public void dump(PrintWriter pw) {
- pw.println("AufoFill UI");
+ pw.println("Autofill UI");
final String prefix = " ";
- pw.print(prefix); pw.print("showsFillUi: "); pw.println(mFillUi != null);
+ final String prefix2 = " ";
pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
pw.print(prefix); pw.print("save timeout: "); pw.println(mSaveTimeoutMs);
+ if (mFillUi != null) {
+ pw.print(prefix); pw.println("showsFillUi: true");
+ mFillUi.dump(pw, prefix2);
+ } else {
+ pw.print(prefix); pw.println("showsFillUi: false");
+ }
}
@android.annotation.UiThread
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index a7d9fe9..a8c8752 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -39,6 +39,7 @@
import com.android.internal.R;
import libcore.util.Objects;
+import java.io.PrintWriter;
import java.util.ArrayList;
final class FillUi {
@@ -50,6 +51,7 @@
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
void onCanceled();
+ void onDestroy();
}
private final Rect mAnchorBounds = new Rect();
@@ -63,6 +65,7 @@
private final @Nullable ArrayAdapter<ViewItem> mAdapter;
private @Nullable String mFilterText;
+ private final String mAccessibilityTitle;
private int mContentWidth;
private int mContentHeight;
@@ -76,6 +79,8 @@
mAnchorBounds.set(anchorBounds);
mCallback = callback;
+ mAccessibilityTitle = context.getString(R.string.autofill_picker_accessibility_title);
+
if (response.getAuthentication() != null) {
mListView = null;
mAdapter = null;
@@ -201,6 +206,7 @@
public void destroy() {
throwIfDestroyed();
+ mCallback.onDestroy();
mWindow.hide();
mDestroyed = true;
}
@@ -319,6 +325,7 @@
public void show(int desiredWidth, int desiredHeight, Rect anchorBounds) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+
params.setTitle("FillUi");
params.token = mActivityToken;
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -327,6 +334,7 @@
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ params.accessibilityTitle = mAccessibilityTitle;
mWm.getDefaultDisplay().getRealSize(mTempPoint);
final int screenWidth = mTempPoint.x;
@@ -377,4 +385,16 @@
}
}
}
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mAnchorBounds: "); pw.println(mAnchorBounds);
+ pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
+ pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
+ pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter != null);
+ pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
+ pw.print(prefix); pw.print("mAccessibilityTitle: "); pw.println(mAccessibilityTitle);
+ pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
+ pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
+ pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/Helper.java b/services/autofill/java/com/android/server/autofill/ui/Helper.java
new file mode 100644
index 0000000..996e421
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/Helper.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+final class Helper {
+
+ static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+ static final boolean VERBOSE = false;
+ private Helper() {
+ throw new UnsupportedOperationException("contains static members only");
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 3f409ad..509351b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -16,6 +16,8 @@
package com.android.server.autofill.ui;
+import static com.android.server.autofill.ui.Helper.DEBUG;
+
import android.annotation.NonNull;
import android.app.Dialog;
import android.content.Context;
@@ -23,6 +25,7 @@
import android.os.Handler;
import android.service.autofill.SaveInfo;
import android.text.format.DateUtils;
+import android.util.Slog;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
@@ -37,22 +40,66 @@
* Autofill Save Prompt
*/
final class SaveUi {
+
+ private static final String TAG = "SaveUi";
+
public interface OnSaveListener {
void onSave();
void onCancel(IntentSender listener);
+ void onDestroy();
+ }
+
+ private class OneTimeListener implements OnSaveListener {
+
+ private final OnSaveListener mRealListener;
+ private boolean mDone;
+
+ OneTimeListener(OnSaveListener realListener) {
+ mRealListener = realListener;
+ }
+
+ @Override
+ public void onSave() {
+ if (DEBUG) Slog.d(TAG, "onSave(): " + mDone);
+ if (mDone) {
+ return;
+ }
+ mDone = true;
+ mRealListener.onSave();
+ }
+
+ @Override
+ public void onCancel(IntentSender listener) {
+ if (DEBUG) Slog.d(TAG, "onCancel(): " + mDone);
+ if (mDone) {
+ return;
+ }
+ mDone = true;
+ mRealListener.onCancel(listener);
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.d(TAG, "onDestroy(): " + mDone);
+ if (mDone) {
+ return;
+ }
+ mDone = true;
+ mRealListener.onDestroy();
+ }
}
private final Handler mHandler = UiThread.getHandler();
private final @NonNull Dialog mDialog;
- private final @NonNull OnSaveListener mListener;
+ private final @NonNull OneTimeListener mListener;
private boolean mDestroyed;
SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@NonNull OnSaveListener listener, int lifeTimeMs) {
- mListener = listener;
+ mListener = new OneTimeListener(listener);
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.autofill_save, null);
@@ -117,11 +164,17 @@
mDialog.show();
- mHandler.postDelayed(() -> mListener.onCancel(null), lifeTimeMs);
+ mHandler.postDelayed(() -> {
+ if (!mListener.mDone) {
+ mListener.onCancel(null);
+ Slog.d(TAG, "Save snackbar timed out after " + lifeTimeMs + "ms");
+ }
+ }, lifeTimeMs);
}
void destroy() {
throwIfDestroyed();
+ mListener.onDestroy();
mHandler.removeCallbacksAndMessages(mListener);
mDialog.dismiss();
mDestroyed = true;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 1864d34..794ece6 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -23,7 +23,9 @@
android.hardware.power@1.0-java \
android.hardware.tv.cec@1.0-java
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ tzdata_shared2 \
+ tzdata_update2 \
android.hidl.base@1.0-java-static \
android.hardware.biometrics.fingerprint@2.1-java-static \
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 34c73d2..c946d09 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1488,7 +1488,7 @@
return VerifyCredentialResponse.OK;
}
- if (TextUtils.isEmpty(credential)) {
+ if (storedHash == null || TextUtils.isEmpty(credential)) {
return VerifyCredentialResponse.ERROR;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3667ecd..8e6310f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2721,7 +2721,7 @@
*/
@Override
public int getPasswordType() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2747,7 +2747,7 @@
*/
@Override
public void setField(String field, String contents) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2767,7 +2767,7 @@
*/
@Override
public String getField(String field) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2793,7 +2793,7 @@
*/
@Override
public boolean isConvertibleToFBE() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2809,7 +2809,7 @@
@Override
public String getPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"only keyguard can retrieve password");
if (!isReady()) {
@@ -2834,7 +2834,7 @@
@Override
public void clearPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"only keyguard can clear password");
if (!isReady()) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index accae0d..f954f75 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -35,7 +35,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
-import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -64,7 +63,6 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;
-import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -80,7 +78,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -113,7 +110,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -158,6 +154,11 @@
public void onUnlockUser(int userHandle) {
mService.onUnlockUser(userHandle);
}
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ mService.onCleanupUser(userHandle);
+ }
}
final Context mContext;
@@ -303,18 +304,6 @@
}
}, intentFilter);
- IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(intent);
- }
- }
- }, UserHandle.ALL, userFilter, null, null);
-
injector.addLocalService(new AccountManagerInternalImpl());
// Need to cancel account request notifications if the update/install can access the account
@@ -1133,16 +1122,12 @@
}
}
- private void onUserRemoved(Intent intent) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId < 1) return;
-
+ private void onCleanupUser(int userId) {
+ Log.i(TAG, "onCleanupUser " + userId);
UserAccounts accounts;
- boolean userUnlocked;
synchronized (mUsers) {
accounts = mUsers.get(userId);
mUsers.remove(userId);
- userUnlocked = mLocalUnlockedUsers.get(userId);
mLocalUnlockedUsers.delete(userId);
}
if (accounts != null) {
@@ -1150,18 +1135,6 @@
accounts.accountsDb.close();
}
}
- Log.i(TAG, "Removing database files for user " + userId);
- File dbFile = new File(mInjector.getDeDatabaseName(userId));
-
- AccountsDb.deleteDbFileWarnIfFailed(dbFile);
- // Remove CE file if user is unlocked, or FBE is not enabled
- boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
- if (!fbeEnabled || userUnlocked) {
- File ceDb = new File(mInjector.getCeDatabaseName(userId));
- if (ceDb.exists()) {
- AccountsDb.deleteDbFileWarnIfFailed(ceDb);
- }
- }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2787895..dd3d4e0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1152,17 +1152,14 @@
skip = true;
}
}
- final boolean visibleToInstantApps =
- (r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
if (!skip && info.activityInfo.applicationInfo.isInstantApp()
- && !visibleToInstantApps
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
+ + " Instant Apps do not support manifest receivers");
skip = true;
}
if (!skip && r.callerInstantApp
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index dec2f77..8c6430c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.tethering;
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
import android.net.INetd;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -48,7 +50,6 @@
public class IPv6TetheringInterfaceServices {
private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
- private static final int RFC7421_IP_PREFIX_LENGTH = 64;
private final String mIfName;
private final INetworkManagementService mNMService;
@@ -124,7 +125,7 @@
params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
- if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue;
+ if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
final IpPrefix prefix = new IpPrefix(
linkAddr.getAddress(), linkAddr.getPrefixLength());
@@ -206,7 +207,7 @@
for (Inet6Address dns : deprecatedDnses) {
final String dnsString = dns.getHostAddress();
try {
- netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+ netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
}
@@ -223,7 +224,7 @@
for (Inet6Address dns : addedDnses) {
final String dnsString = dns.getHostAddress();
try {
- netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+ netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
newDnses.remove(dns);
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3262151..bdba64f 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -97,7 +97,6 @@
static final String TAG = "FingerprintService";
static final boolean DEBUG = true;
private static final String FP_DATA_DIR = "fpdata";
- private static final String FINGERPRINT_HIDL = "fingerprint_hal";
private static final int MSG_USER_SWITCHING = 10;
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
@@ -219,7 +218,7 @@
public synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
try {
- mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL);
+ mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened. Logged below.
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8280946..3dcc5d9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,10 +22,10 @@
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static android.service.notification.NotificationListenerService.REASON_ERROR;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
@@ -88,7 +88,6 @@
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.IRingtonePlayer;
-import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -159,8 +158,6 @@
import libcore.io.IoUtils;
-import com.google.android.collect.Lists;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -181,7 +178,6 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -545,7 +541,7 @@
@Override
public void onClearAll(int callingUid, int callingPid, int userId) {
synchronized (mNotificationLock) {
- cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
+ cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
/*includeCurrentProfiles*/ true);
}
}
@@ -569,7 +565,7 @@
cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
- REASON_DELEGATE_CLICK, null);
+ REASON_CLICK, null);
}
}
@@ -598,7 +594,7 @@
String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
- true, userId, REASON_DELEGATE_CANCEL, null);
+ true, userId, REASON_CANCEL, null);
}
@Override
@@ -633,7 +629,7 @@
Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
+ "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
- REASON_DELEGATE_ERROR, null);
+ REASON_ERROR, null);
long ident = Binder.clearCallingIdentity();
try {
ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
@@ -3377,7 +3373,7 @@
Slog.e(TAG, "Not posting notification without small icon: " + notification);
if (old != null && !old.isCanceled) {
mListeners.notifyRemovedLocked(n,
- NotificationListenerService.REASON_DELEGATE_ERROR);
+ NotificationListenerService.REASON_ERROR);
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -4024,8 +4020,8 @@
// Record usage stats
// TODO: add unbundling stats?
switch (reason) {
- case REASON_DELEGATE_CANCEL:
- case REASON_DELEGATE_CANCEL_ALL:
+ case REASON_CANCEL:
+ case REASON_CANCEL_ALL:
case REASON_LISTENER_CANCEL:
case REASON_LISTENER_CANCEL_ALL:
mUsageStats.registerDismissedByUser(r);
@@ -4085,7 +4081,7 @@
// Ideally we'd do this in the caller of this method. However, that would
// require the caller to also find the notification.
- if (reason == REASON_DELEGATE_CLICK) {
+ if (reason == REASON_CLICK) {
mUsageStats.registerClickedByUser(r);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d763808..1d1bf0d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2038,12 +2038,15 @@
final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
+ final boolean instantApp = isInstantApp(pkg.packageName, userId);
+
for (String permission : pkg.requestedPermissions) {
final BasePermission bp;
synchronized (mPackages) {
bp = mSettings.mPermissions.get(permission);
}
if (bp != null && (bp.isRuntime() || bp.isDevelopment())
+ && (!instantApp || bp.isInstant())
&& (grantedPermissions == null
|| ArrayUtils.contains(grantedPermissions, permission))) {
final int flags = permissionsState.getPermissionFlags(permission, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a7349fc..751d9af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -147,6 +147,8 @@
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
+ case "has-feature":
+ return runHasFeature();
default:
return handleDefaultCommands(cmd);
}
@@ -1268,6 +1270,28 @@
return 0;
}
+ private int runHasFeature() {
+ final PrintWriter err = getErrPrintWriter();
+ final String featureName = getNextArg();
+ if (featureName == null) {
+ err.println("Error: expected FEATURE name");
+ return 1;
+ }
+ final String versionString = getNextArg();
+ try {
+ final int version = (versionString == null) ? 0 : Integer.parseInt(versionString);
+ final boolean hasFeature = mInterface.hasSystemFeature(featureName, version);
+ getOutPrintWriter().println(hasFeature);
+ return hasFeature ? 0 : 1;
+ } catch (NumberFormatException e) {
+ err.println("Error: illegal version number " + versionString);
+ return 1;
+ } catch (RemoteException e) {
+ err.println(e.toString());
+ return 1;
+ }
+ }
+
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
@@ -1649,6 +1673,9 @@
pw.println(" Unsuspends the specified package (as user).");
pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
pw.println(" set the default home activity (aka launcher).");
+ pw.println(" has-feature FEATURE_NAME [version]");
+ pw.println(" prints true and returns exit status 0 when system has a FEATURE_NAME,");
+ pw.println(" otherwise prints false and returns exit status 1");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b9fcf4e..1f97d7d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1810,8 +1810,8 @@
if (type == XmlPullParser.START_TAG) {
if (parser.getName().equals(TAG_RESTRICTIONS)) {
synchronized (mGuestRestrictions) {
- mGuestRestrictions.putAll(
- UserRestrictionsUtils.readRestrictions(parser));
+ UserRestrictionsUtils
+ .readRestrictions(parser, mGuestRestrictions);
}
}
break;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 36eba8e..cb2ed6e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -207,6 +207,7 @@
}
public static void readRestrictions(XmlPullParser parser, Bundle restrictions) {
+ restrictions.clear();
for (String key : USER_RESTRICTIONS) {
final String value = parser.getAttributeValue(null, key);
if (value != null) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index 5e17daa..8f95cc7 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -1,6 +1,8 @@
package com.android.server.vr;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -86,10 +88,8 @@
startVirtualDisplay();
}
} else {
- // TODO: Remove conditional when launching apps 2D doesn't force VrMode to stop.
- if (!DEBUG) {
- stopVirtualDisplay();
- }
+ // Stop virtual display to test exit condition
+ stopVirtualDisplay();
}
}
@@ -138,6 +138,19 @@
}
}
+ public int getVirtualDisplayId() {
+ synchronized(vdLock) {
+ if (mVirtualDisplay != null) {
+ int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
+ if (DEBUG) {
+ Log.e(TAG, "VD id: " + virtualDisplayId);
+ }
+ return virtualDisplayId;
+ }
+ }
+ return INVALID_DISPLAY;
+ }
+
private void startVirtualDisplay() {
if (DEBUG) {
Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 58e4bdc..210aa44 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -90,6 +90,15 @@
public abstract void setPersistentVrModeEnabled(boolean enabled);
/**
+ * Return {@link android.view.Display.INVALID_DISPLAY} if there exists no virtual display
+ * currently or the display id of the current virtual display.
+ *
+ * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+ * currently, else return the display id of the virtual display
+ */
+ public abstract int getCompatibilityDisplayId();
+
+ /**
* Adds listener that reports state changes to persistent VR mode.
*/
public abstract void addPersistentVrModeStateListener(PersistentVrStateListener listener);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 8a23173..a00115c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -15,6 +15,8 @@
*/
package com.android.server.vr;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@@ -392,6 +394,11 @@
}
@Override
+ public int getCompatibilityDisplayId() {
+ return VrManagerService.this.getCompatibilityDisplayId();
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -495,6 +502,11 @@
}
@Override
+ public int getCompatibilityDisplayId() {
+ return VrManagerService.this.getCompatibilityDisplayId();
+ }
+
+ @Override
public void addPersistentVrModeStateListener(PersistentVrStateListener listener) {
VrManagerService.this.addPersistentVrModeStateListener(listener);
}
@@ -1054,6 +1066,14 @@
}
}
+ private int getCompatibilityDisplayId() {
+ if (mCompatibilityDisplay != null) {
+ return mCompatibilityDisplay.getVirtualDisplayId();
+ }
+ Slog.w(TAG, "CompatibilityDisplay is null!");
+ return INVALID_DISPLAY;
+ }
+
private void setPersistentModeAndNotifyListenersLocked(boolean enabled) {
if (mPersistentVrModeEnabled == enabled) {
return;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 4df513e..30e0ded 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -28,7 +28,6 @@
import android.content.ClipData;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
@@ -39,6 +38,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
@@ -216,13 +216,13 @@
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
- Configuration outConfig, Surface outSurface) {
+ MergedConfiguration mergedConfiguration, Surface outSurface) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
- outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
+ outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
return res;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c0598ca..04403e2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -27,7 +27,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.ActivityManager.TaskDescription;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -38,6 +37,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.IWindowSession;
import android.view.Surface;
@@ -78,7 +78,7 @@
final Surface surface = new Surface();
final Rect tmpRect = new Rect();
final Rect tmpFrame = new Rect();
- final Configuration tmpConfiguration = new Configuration();
+ final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
int fillBackgroundColor = Color.WHITE;
synchronized (service.mWindowMap) {
layoutParams.type = TYPE_APPLICATION_STARTING;
@@ -122,7 +122,7 @@
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
- tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration,
+ tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration,
surface);
} catch (RemoteException e) {
// Local call.
@@ -221,9 +221,9 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
- Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar,
- int displayId) {
+ Rect stableInsets, Rect outsets, boolean reportDraw,
+ MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
+ boolean alwaysConsumeNavBar, int displayId) {
if (reportDraw) {
sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5551afe..7539cd4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -150,6 +150,7 @@
import android.os.WorkSource;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.MergedConfiguration;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -1813,7 +1814,7 @@
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
- Configuration outConfig, Surface outSurface) {
+ MergedConfiguration mergedConfiguration, Surface outSurface) {
int result = 0;
boolean configChanged;
boolean hasStatusBarPermission =
@@ -1925,7 +1926,7 @@
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
|| !win.mAppToken.clientHidden)) {
- result = win.relayoutVisibleWindow(outConfig, result, attrChanges,
+ result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
oldVisibility);
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4e593d8..ca5d551 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -114,6 +114,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.util.MergedConfiguration;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.TimeUtils;
@@ -2265,7 +2266,7 @@
}
}
- void prepareWindowToDisplayDuringRelayout(Configuration outConfig) {
+ void prepareWindowToDisplayDuringRelayout(MergedConfiguration mergedConfiguration) {
if ((mAttrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
== SOFT_INPUT_ADJUST_RESIZE) {
mLayoutNeeded = true;
@@ -2278,10 +2279,13 @@
mTurnOnScreen = true;
}
if (isConfigChanged()) {
- outConfig.setTo(getConfiguration());
- if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
- + outConfig);
- mLastReportedConfiguration.setTo(outConfig);
+ final Configuration globalConfig = mService.mRoot.getConfiguration();
+ final Configuration overrideConfig = getMergedOverrideConfiguration();
+ mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
+ if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
+ + " visible with new global config: " + globalConfig
+ + " merged override config: " + overrideConfig);
+ mLastReportedConfiguration.setTo(getConfiguration());
}
}
@@ -3027,12 +3031,13 @@
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ ": " + mCompatFrame);
- final Configuration newConfig;
+ final MergedConfiguration mergedConfiguration;
if (isConfigChanged()) {
- newConfig = new Configuration(getConfiguration());
- mLastReportedConfiguration.setTo(newConfig);
+ mergedConfiguration = new MergedConfiguration(mService.mRoot.getConfiguration(),
+ getMergedOverrideConfiguration());
+ mLastReportedConfiguration.setTo(mergedConfiguration.getMergedConfiguration());
} else {
- newConfig = null;
+ mergedConfiguration = null;
}
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -3054,7 +3059,7 @@
public void run() {
try {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
- stableInsets, outsets, reportDraw, newConfig,
+ stableInsets, outsets, reportDraw, mergedConfiguration,
reportOrientation, displayId);
} catch (RemoteException e) {
// Not a remote call, RemoteException won't be raised.
@@ -3063,7 +3068,7 @@
});
} else {
dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, newConfig, reportOrientation, displayId);
+ outsets, reportDraw, mergedConfiguration, reportOrientation, displayId);
}
//TODO (multidisplay): Accessibility supported only for the default display.
@@ -3120,14 +3125,14 @@
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, boolean reportOrientation, int displayId)
+ MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId)
throws RemoteException {
final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing
|| reportOrientation;
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
- reportDraw, newConfig, getBackdropFrame(frame),
- forceRelayout, mPolicy.isNavBarForcedShownLw(this), displayId);
+ reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
+ mPolicy.isNavBarForcedShownLw(this), displayId);
mDragResizingChangeReported = true;
}
@@ -4341,8 +4346,8 @@
return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets);
}
- int relayoutVisibleWindow(Configuration outConfig, int result,
- int attrChanges, int oldVisibility) {
+ int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges,
+ int oldVisibility) {
result |= !isVisibleLw() ? RELAYOUT_RES_FIRST_TIME : 0;
if (mAnimatingExit) {
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
@@ -4363,7 +4368,7 @@
mWinAnimator.mEnteringAnimation = true;
if ((result & RELAYOUT_RES_FIRST_TIME) != 0) {
- prepareWindowToDisplayDuringRelayout(outConfig);
+ prepareWindowToDisplayDuringRelayout(mergedConfiguration);
}
if ((attrChanges & FORMAT_CHANGED) != 0) {
// If the format can't be changed in place, preserve the old surface until the app draws
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index ac95db5..b5ed266 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -65,6 +65,7 @@
libinputflinger \
libinputservice \
libsensorservice \
+ libsensorservicehidl \
libskia \
libgui \
libusbhost \
@@ -88,5 +89,6 @@
android.hardware.tv.input@1.0 \
android.hardware.vibrator@1.0 \
android.hardware.vr@1.0 \
+ android.frameworks.sensorservice@1.0 \
-LOCAL_STATIC_LIBRARIES += libscrypt_static
\ No newline at end of file
+LOCAL_STATIC_LIBRARIES += libscrypt_static
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3120af56..8ad88ed 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -17,7 +17,10 @@
#include <jni.h>
#include <JNIHelp.h>
+#include <hidl/HidlTransportSupport.h>
+
#include <sensorservice/SensorService.h>
+#include <sensorservicehidl/SensorManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
@@ -32,6 +35,21 @@
if (strcmp(propBuf, "1") == 0) {
SensorService::instantiate();
}
+
+}
+
+static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
+ using ::android::frameworks::sensorservice::V1_0::ISensorManager;
+ using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+ using ::android::hardware::configureRpcThreadpool;
+
+ configureRpcThreadpool(1, false /* callerWillJoin */);
+ sp<ISensorManager> sensorService = new SensorManager();
+ status_t err = sensorService->registerAsService();
+ if (err != OK) {
+ ALOGE("Cannot register ::android::frameworks::sensorservice::V1_0::"
+ "implementation::SensorManager: %d", err);
+ }
}
/*
@@ -40,6 +58,7 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
+ { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f84bfef..e6e0242 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -236,16 +236,24 @@
private final boolean mRuntimeRestart;
private static final String START_SENSOR_SERVICE = "StartSensorService";
+ private static final String START_HIDL_SERVICES = "StartHidlServices";
+
+
private Future<?> mSensorServiceStart;
private Future<?> mZygotePreload;
-
/**
* Start the sensor service. This is a blocking call and can take time.
*/
private static native void startSensorService();
/**
+ * Start all HIDL services that are run inside the system server. This
+ * may take some time.
+ */
+ private static native void startHidlServices();
+
+ /**
* The main entry point from zygote.
*/
public static void main(String[] args) {
@@ -611,6 +619,7 @@
startSensorService();
traceLog.traceEnd();
}, START_SENSOR_SERVICE);
+
}
/**
@@ -638,6 +647,14 @@
traceBeginAndSlog("StartWebViewUpdateService");
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
traceEnd();
+
+ // Start receiving calls from HIDL services. Start in in a separate thread
+ // because it need to connect to SensorManager.
+ SystemServerInitThreadPool.get().submit(() -> {
+ traceBeginAndSlog(START_HIDL_SERVICES);
+ startHidlServices();
+ traceEnd();
+ }, START_HIDL_SERVICES);
}
/**
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 3e3a19b..c670782 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -16,6 +16,8 @@
package android.net.ip;
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
import com.android.internal.util.MessageUtils;
import com.android.internal.util.WakeupMessage;
@@ -42,6 +44,7 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -1028,15 +1031,36 @@
return true;
}
- private boolean startIPv6() {
- // Set privacy extensions.
+ private void enableInterfaceIPv6PrivacyExtensions() {
final String PREFER_TEMPADDRS = "2";
+ NetdService.run((INetd netd) -> {
+ netd.setProcSysNet(
+ INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", PREFER_TEMPADDRS);
+ });
+ }
+
+ private void setInterfaceIPv6RaRtInfoMaxPlen(int plen) {
+ // Setting RIO max plen is best effort. Catch and ignore most exceptions.
try {
NetdService.run((INetd netd) -> {
- netd.setProcSysNet(
- INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
- PREFER_TEMPADDRS);
- });
+ netd.setProcSysNet(
+ INetd.IPV6, INetd.CONF, mInterfaceName, "accept_ra_rt_info_max_plen",
+ Integer.toString(plen));
+ });
+ } catch (ServiceSpecificException e) {
+ // Old kernel versions without support for RIOs do not export accept_ra_rt_info_max_plen
+ // in the /proc filesystem. If the kernel supports RIOs we should never see any other
+ // type of error.
+ if (e.errorCode != OsConstants.ENOENT) {
+ logError("unexpected error setting accept_ra_rt_info_max_plen %s", e);
+ }
+ }
+ }
+
+ private boolean startIPv6() {
+ try {
+ enableInterfaceIPv6PrivacyExtensions();
+ setInterfaceIPv6RaRtInfoMaxPlen(RFC7421_PREFIX_LENGTH);
mNwService.enableIpv6(mInterfaceName);
} catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
logError("Unable to change interface settings: %s", e);
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 362f757..26f3050 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -97,6 +97,7 @@
public static final int IPV6_SRC_ADDR_OFFSET = 8;
public static final int IPV6_DST_ADDR_OFFSET = 24;
public static final int IPV6_ADDR_LEN = 16;
+ public static final int RFC7421_PREFIX_LENGTH = 64;
/**
* ICMPv6 constants.
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 9f50a2c..921e0e3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -126,8 +126,6 @@
}
@Test
- @Ignore
- // TODO(b/35034729): Need to fix before re-enabling
public void testLandscapeSeascapeRotationByPolicy() throws Exception {
// Some plumbing to get the service ready for rotation updates.
sWm.mDisplayReady = true;
@@ -145,15 +143,20 @@
appWindowToken.addWindow(appWindow);
// Set initial orientation and update.
- ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_90;
- sWm.updateRotation(false, false);
+ performRotation(Surface.ROTATION_90);
appWindow.resizeReported = false;
// Update the rotation to perform 180 degree rotation and check that resize was reported.
- ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_270;
- sWm.updateRotation(false, false);
- sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ performRotation(Surface.ROTATION_270);
assertTrue(appWindow.resizeReported);
appWindow.removeImmediately();
}
+
+ private void performRotation(int rotationToReport) {
+ ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = rotationToReport;
+ sWm.updateRotation(false, false);
+ // Simulate animator finishing orientation change
+ sWm.mRoot.mOrientationChangeComplete = true;
+ sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index b6dc9a5..0a644b60 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -18,11 +18,11 @@
import com.android.internal.os.IResultReceiver;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.MergedConfiguration;
import android.view.DragEvent;
import android.view.IWindow;
@@ -36,7 +36,7 @@
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig,
+ Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId)
throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 911050a..65efd9c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -71,7 +71,10 @@
static TestWindowManagerPolicy sPolicy = null;
private final static IWindow sIWindow = new TestIWindow();
private final static Session sMockSession = mock(Session.class);
- private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
+ // The default display is removed in {@link #setUp} and then we iterate over all displays to
+ // make sure we don't collide with any existing display. If we run into no other display, the
+ // added display should be treated as default.
+ private static int sNextDisplayId = Display.DEFAULT_DISPLAY;
static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
private static int sNextTaskId = 0;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 40bdaa5..03d8241 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -25,8 +25,8 @@
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
-import android.os.FileObserver;
import android.os.Bundle;
+import android.os.FileObserver;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -41,10 +41,7 @@
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.HashMap;
-import java.util.ArrayList;
/**
* UsbAlsaManager manages USB audio and MIDI devices.
@@ -219,23 +216,23 @@
AlsaDevice testDevice = new AlsaDevice(type, card, device);
// This value was empirically determined.
- final int kWaitTime = 2500; // ms
+ final int kWaitTimeMs = 2500;
synchronized(mAlsaDevices) {
- long timeout = SystemClock.elapsedRealtime() + kWaitTime;
+ long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs;
do {
if (mAlsaDevices.values().contains(testDevice)) {
return testDevice;
}
- long waitTime = timeout - SystemClock.elapsedRealtime();
- if (waitTime > 0) {
+ long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime();
+ if (waitTimeMs > 0) {
try {
- mAlsaDevices.wait(waitTime);
+ mAlsaDevices.wait(waitTimeMs);
} catch (InterruptedException e) {
Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
}
}
- } while (timeout > SystemClock.elapsedRealtime());
+ } while (timeoutMs > SystemClock.elapsedRealtime());
}
Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
@@ -498,6 +495,7 @@
// Devices List
//
/*
+ //import java.util.ArrayList;
public ArrayList<UsbAudioDevice> getConnectedDevices() {
ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 808b5d3..a7bdabd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -138,7 +138,7 @@
mSaturation = saturation;
final ColorMatrixColorFilter filter =
(ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter();
- final ColorMatrix m = filter.getColorMatrix();
+ final ColorMatrix m = new ColorMatrix();
m.setSaturation(saturation);
filter.setColorMatrix(m);
invalidate();
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
index 58399fd..759bc35 100644
--- a/tests/testables/Android.mk
+++ b/tests/testables/Android.mk
@@ -25,7 +25,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-updated-target-minus-junit4 \
+ mockito-target-minus-junit4 \
legacy-android-test
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk
index 752d536..a123d80 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -27,7 +27,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-updated-target-minus-junit4 \
+ mockito-target-minus-junit4 \
legacy-android-test \
testables
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index bd934d0..cb013b6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -66,7 +66,7 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void destroyFilter(long native_instance) {
+ /*package*/ static void nSafeUnref(long native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 4689491..ffbe7c4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -18,12 +18,12 @@
import com.android.internal.os.IResultReceiver;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.MergedConfiguration;
import android.view.DragEvent;
import android.view.IWindow;
@@ -50,7 +50,7 @@
@Override
public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
- boolean b, Configuration configuration, Rect rect7, boolean b2, boolean b3, int i0)
+ boolean b, MergedConfiguration mergedConfig, Rect rect7, boolean b2, boolean b3, int i0)
throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 4dfe47b..2c88394 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -17,12 +17,12 @@
package com.android.layoutlib.bridge.android;
import android.content.ClipData;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.MergedConfiguration;
import android.view.IWindow;
import android.view.IWindowId;
import android.view.IWindowSession;
@@ -89,7 +89,7 @@
@Override
public int relayout(IWindow iWindow, int i, LayoutParams layoutParams, int i2,
int i3, int i4, int i5, Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5,
- Rect rect6, Rect rect7, Configuration configuration, Surface surface)
+ Rect rect6, Rect rect7, MergedConfiguration mergedConfig, Surface surface)
throws RemoteException {
// pass for now.
return 0;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a1099f8..04f9059 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -281,7 +281,9 @@
public int apChannel = 0;
/**
- * Pre-shared key for use with WPA-PSK.
+ * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in
+ * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or
+ * a string of 64 hex digits for raw PSK.
* <p/>
* When the value of this key is read, the actual key is
* not returned, just a "*" if the key has a value, or the null
@@ -305,7 +307,7 @@
/**
* Priority determines the preference given to a network by {@code wpa_supplicant}
* when choosing an access point with which to associate.
- * @deprecated Priority is no longer used.
+ * @deprecated This field does not exist anymore.
*/
@Deprecated
public int priority;
@@ -434,6 +436,13 @@
public int dtimInterval = 0;
/**
+ * Flag indicating if this configuration represents a legacy Passpoint configuration
+ * (Release N or older). This is used for migrating Passpoint configuration from N to O.
+ * This will no longer be needed after O.
+ * @hide
+ */
+ public boolean isLegacyPasspointConfig = false;
+ /**
* @hide
* Uid of app creating the configuration
*/
@@ -1961,6 +1970,7 @@
mCachedConfigKey = null; //force null configKey
selfAdded = source.selfAdded;
validatedInternetAccess = source.validatedInternetAccess;
+ isLegacyPasspointConfig = source.isLegacyPasspointConfig;
ephemeral = source.ephemeral;
meteredHint = source.meteredHint;
meteredOverride = source.meteredOverride;
@@ -2037,6 +2047,7 @@
dest.writeInt(selfAdded ? 1 : 0);
dest.writeInt(didSelfAdd ? 1 : 0);
dest.writeInt(validatedInternetAccess ? 1 : 0);
+ dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(meteredHint ? 1 : 0);
dest.writeInt(meteredOverride ? 1 : 0);
@@ -2103,6 +2114,7 @@
config.selfAdded = in.readInt() != 0;
config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
+ config.isLegacyPasspointConfig = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.meteredHint = in.readInt() != 0;
config.meteredOverride = in.readInt() != 0;