diff options
98 files changed, 1994 insertions, 910 deletions
diff --git a/api/current.txt b/api/current.txt index d2c67adf491b..40cb282cb1c1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4208,6 +4208,12 @@ package android.app { public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 { ctor public Application(); + method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String); + method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String); + method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String); + method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent); method public void onConfigurationChanged(android.content.res.Configuration); method public void onCreate(); method public void onLowMemory(); diff --git a/api/system-current.txt b/api/system-current.txt index 648bb54ac711..3231b4d40dfe 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4363,6 +4363,12 @@ package android.app { public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 { ctor public Application(); + method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String); + method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String); + method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String); + method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent); method public void onConfigurationChanged(android.content.res.Configuration); method public void onCreate(); method public void onLowMemory(); diff --git a/api/test-current.txt b/api/test-current.txt index 2530d6849248..bc05da67c38f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4221,6 +4221,12 @@ package android.app { public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 { ctor public Application(); + method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String); + method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String); + method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String); + method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent); + method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent); method public void onConfigurationChanged(android.content.res.Configuration); method public void onCreate(); method public void onLowMemory(); diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 71be63237739..23668786abee 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -253,5 +253,5 @@ int main(int argc, char** argv) } // b/36066697: Avoid running static destructors. - _exit(1); + _exit(0); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 905a3ee9d25b..f868d475fc7b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2678,8 +2678,14 @@ public final class ActivityThread { Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); - activity = mInstrumentation.newActivity( - cl, component.getClassName(), r.intent); + if (appContext.getApplicationContext() instanceof Application) { + activity = ((Application) appContext.getApplicationContext()) + .instantiateActivity(cl, component.getClassName(), r.intent); + } + if (activity == null) { + activity = mInstrumentation.newActivity( + cl, component.getClassName(), r.intent); + } StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); @@ -3204,7 +3210,8 @@ public final class ActivityThread { data.intent.setExtrasClassLoader(cl); data.intent.prepareToEnterProcess(); data.setExtrasClassLoader(cl); - receiver = (BroadcastReceiver)cl.loadClass(component).newInstance(); + receiver = instantiate(cl, component, data.intent, app, + Application::instantiateReceiver); } catch (Exception e) { if (DEBUG_BROADCAST) Slog.i(TAG, "Finishing failed broadcast to " + data.intent.getComponent()); @@ -3292,12 +3299,13 @@ public final class ActivityThread { } else { try { if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname); + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); java.lang.ClassLoader cl = packageInfo.getClassLoader(); - agent = (BackupAgent) cl.loadClass(classname).newInstance(); + agent = instantiate(cl, classname, context, + Application::instantiateBackupAgent); // set up the agent's context - ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(agent); agent.attach(context); @@ -3357,9 +3365,12 @@ public final class ActivityThread { LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; + Application app = null; try { + app = packageInfo.makeApplication(false, mInstrumentation); java.lang.ClassLoader cl = packageInfo.getClassLoader(); - service = (Service) cl.loadClass(data.info.name).newInstance(); + service = instantiate(cl, data.info.name, data.intent, app, + Application::instantiateService); } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException( @@ -3374,7 +3385,6 @@ public final class ActivityThread { ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service); - Application app = packageInfo.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); service.onCreate(); @@ -5691,8 +5701,8 @@ public final class ActivityThread { try { final ClassLoader cl = instrContext.getClassLoader(); - mInstrumentation = (Instrumentation) - cl.loadClass(data.instrumentationName.getClassName()).newInstance(); + mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(), + instrContext, Application::instantiateInstrumentation); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate instrumentation " @@ -6237,8 +6247,8 @@ public final class ActivityThread { try { final java.lang.ClassLoader cl = c.getClassLoader(); - localProvider = (ContentProvider)cl. - loadClass(info.name).newInstance(); + localProvider = instantiate(cl, info.name, context, + Application::instantiateProvider); provider = localProvider.getIContentProvider(); if (provider == null) { Slog.e(TAG, "Failed to instantiate class " + @@ -6437,6 +6447,38 @@ public final class ActivityThread { } } + private <T> T instantiate(ClassLoader cl, String className, Context c, + Instantiator<T> instantiator) + throws ClassNotFoundException, IllegalAccessException, InstantiationException { + if (c.getApplicationContext() instanceof Application) { + T a = instantiator.instantiate((Application) c.getApplicationContext(), + cl, className); + if (a != null) return a; + } + return (T) cl.loadClass(className).newInstance(); + } + + private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c, + IntentInstantiator<T> instantiator) + throws ClassNotFoundException, IllegalAccessException, InstantiationException { + if (c.getApplicationContext() instanceof Application) { + T a = instantiator.instantiate((Application) c.getApplicationContext(), + cl, className, intent); + if (a != null) return a; + } + return (T) cl.loadClass(className).newInstance(); + } + + private interface Instantiator<T> { + T instantiate(Application app, ClassLoader cl, String className) + throws ClassNotFoundException, IllegalAccessException, InstantiationException; + } + + private interface IntentInstantiator<T> { + T instantiate(Application app, ClassLoader cl, String className, Intent intent) + throws ClassNotFoundException, IllegalAccessException, InstantiationException; + } + private static class EventLoggingReporter implements EventLogger.Reporter { @Override public void report (int code, Object... list) { diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 156df36a600c..cc23ec9023b6 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -16,17 +16,20 @@ package android.app; -import java.util.ArrayList; - import android.annotation.CallSuper; +import android.app.backup.BackupAgent; +import android.content.BroadcastReceiver; import android.content.ComponentCallbacks; import android.content.ComponentCallbacks2; +import android.content.ContentProvider; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; +import java.util.ArrayList; + /** * Base class for maintaining global application state. You can provide your own * implementation by creating a subclass and specifying the fully-qualified name @@ -289,4 +292,73 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } } } + + /** + * Allows application to override the creation of activities. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + * @param intent Intent creating the class. + */ + public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) { + return null; + } + + /** + * Allows application to override the creation of receivers. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + * @param intent Intent creating the class. + */ + public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) { + return null; + } + + /** + * Allows application to override the creation of services. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + * @param intent Intent creating the class. + */ + public Service instantiateService(ClassLoader cl, String className, Intent intent) { + return null; + } + + /** + * Allows application to override the creation of providers. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + */ + public ContentProvider instantiateProvider(ClassLoader cl, String className) { + return null; + } + + /** + * Allows application to override the creation of backup agents. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + */ + public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) { + return null; + } + + /** + * Allows application to override the creation of instrumentation. This can be used to + * perform things such as dependency injection or class loader changes to these + * classes. Return null to use the default creation flow. + * @param cl The default classloader to use for instantiation. + * @param className The class to be instantiated. + */ + public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) { + return null; + } }
\ No newline at end of file diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index a040520ffb9f..318c7ac31522 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2157,6 +2157,14 @@ class ContextImpl extends Context { } @Override + public boolean canLoadUnsafeResources() { + if (getPackageName().equals(getOpPackageName())) { + return true; + } + return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0; + } + + @Override public Display getDisplay() { if (mDisplay == null) { return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY, diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java index 33f4e8060b3e..7d6ad2119fb7 100644 --- a/core/java/android/app/timezone/RulesState.java +++ b/core/java/android/app/timezone/RulesState.java @@ -174,29 +174,14 @@ public final class RulesState implements Parcelable { } /** - * Returns true if the distro IANA rules version supplied is newer or the same as the version in - * the system image data files. + * Returns true if the system image data files contain IANA rules data that are newer than the + * distro IANA rules version supplied, i.e. true when the version specified would be "worse" + * than the one that is in the system image. Returns false if the system image version is the + * same or older, i.e. false when the version specified would be "better" than the one that is + * in the system image. */ - public boolean isSystemVersionOlderThan(DistroRulesVersion distroRulesVersion) { - return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) < 0; - } - - public boolean isDistroInstalled() { - return mDistroStatus == DISTRO_STATUS_INSTALLED; - } - - /** - * Returns true if the rules version supplied is newer than the one currently installed. If - * there is no installed distro this method throws IllegalStateException. - */ - public boolean isInstalledDistroOlderThan(DistroRulesVersion distroRulesVersion) { - if (mOperationInProgress) { - throw new IllegalStateException("Distro state not known: operation in progress."); - } - if (!isDistroInstalled()) { - throw new IllegalStateException("No distro installed."); - } - return mInstalledDistroRulesVersion.isOlderThan(distroRulesVersion); + public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) { + return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0; } public static final Parcelable.Creator<RulesState> CREATOR = diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index f3f0ae5cd959..1eac395bd06c 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -136,6 +136,11 @@ public final class BluetoothLeScanner { * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via * the PendingIntent. Use this method of scanning if your process is not always running and it * should be started when scan results are available. + * <p> + * When the PendingIntent is delivered, the Intent passed to the receiver or activity + * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE}, + * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of + * the scan. * * @param filters Optional list of ScanFilters for finding exact BLE devices. * @param settings Optional settings for the scan. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5929aca0a38f..ef6170359dda 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4681,6 +4681,12 @@ public abstract class Context { public abstract boolean isCredentialProtectedStorage(); /** + * Returns true if the context can load unsafe resources, e.g. fonts. + * @hide + */ + public abstract boolean canLoadUnsafeResources(); + + /** * @hide */ public IBinder getActivityToken() { diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index c719c6474cf1..a9fd58bc950c 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -925,6 +925,12 @@ public class ContextWrapper extends Context { return mBase.isCredentialProtectedStorage(); } + /** {@hide} */ + @Override + public boolean canLoadUnsafeResources() { + return mBase.canLoadUnsafeResources(); + } + /** * @hide */ diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 434cf51bbefc..99bf25520458 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -1486,7 +1486,7 @@ public class RadioManager { return nativeListModules(modules); } - Log.v(TAG, "Listing available tuners..."); + Log.d(TAG, "Listing available tuners..."); List<ModuleProperties> returnedList; try { returnedList = mService.listModules(); @@ -1527,7 +1527,7 @@ public class RadioManager { } if (mService != null) { - Log.d(TAG, "Opening tuner..."); + Log.d(TAG, "Opening tuner " + moduleId + "..."); ITuner tuner; ITunerCallback halCallback = new TunerCallbackAdapter(callback, handler); diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java index d07b40759be7..07dd5dbe0e18 100644 --- a/core/java/android/hardware/radio/RadioMetadata.java +++ b/core/java/android/hardware/radio/RadioMetadata.java @@ -15,21 +15,16 @@ */ package android.hardware.radio; -import android.annotation.NonNull; import android.annotation.SystemApi; -import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; -import java.util.ArrayList; import java.util.Set; /** @@ -540,7 +535,6 @@ public final class RadioMetadata implements Parcelable { } int putClockFromNative(int nativeKey, long utcEpochSeconds, int timezoneOffsetInMinutes) { - Log.d(TAG, "putClockFromNative()"); String key = getKeyFromNativeKey(nativeKey); if (!METADATA_KEYS_TYPE.containsKey(key) || METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_CLOCK) { diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java index 710dc1021dd8..dbaca62e639f 100644 --- a/core/java/android/hardware/radio/TunerAdapter.java +++ b/core/java/android/hardware/radio/TunerAdapter.java @@ -43,7 +43,7 @@ class TunerAdapter extends RadioTuner { public void close() { synchronized (mTuner) { if (mIsClosed) { - Log.d(TAG, "Tuner is already closed"); + Log.v(TAG, "Tuner is already closed"); return; } mIsClosed = true; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f47807142376..511466ae01c3 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -599,7 +599,7 @@ public class ConnectivityManager { /** * @hide */ - public final static int REQUEST_ID_UNSET = 0; + public static final int REQUEST_ID_UNSET = 0; /** * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered. @@ -607,7 +607,7 @@ public class ConnectivityManager { * registered and those that were already unregistered. * @hide */ - private final static NetworkRequest ALREADY_UNREGISTERED = + private static final NetworkRequest ALREADY_UNREGISTERED = new NetworkRequest.Builder().clearCapabilities().build(); /** diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index c34de1551ebf..92e78bc8d977 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -97,6 +97,12 @@ interface INetworkManagementService void enableIpv6(String iface); /** + * Set IPv6 autoconf address generation mode. + * This is a no-op if an unsupported mode is requested. + */ + void setIPv6AddrGenMode(String iface, int mode); + + /** * Enables or enables IPv6 ND offload. */ void setInterfaceIpv6NdOffload(String iface, boolean enable); diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 74ff6dc0ec7f..a8c6aa6cbbbb 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -18,6 +18,7 @@ package android.text; import android.annotation.Nullable; import android.graphics.Paint; +import android.os.LocaleList; import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan.LeadingMarginSpan2; import android.text.style.LineHeightSpan; @@ -333,6 +334,16 @@ public class StaticLayout extends Layout { return this; } + private long[] getHyphenators(LocaleList locales) { + final int length = locales.size(); + final long[] result = new long[length]; + for (int i = 0; i < length; i++) { + final Locale locale = locales.get(i); + result[i] = Hyphenator.get(locale).getNativePtr(); + } + return result; + } + /** * Measurement and break iteration is done in native code. The protocol for using * the native code is as follows. @@ -342,7 +353,7 @@ public class StaticLayout extends Layout { * future). * * Then, for each run within the paragraph: - * - setLocale (this must be done at least for the first run, optional afterwards) + * - setLocales (this must be done at least for the first run, optional afterwards) * - one of the following, depending on the type of run: * + addStyleRun (a text run, to be measured in native code) * + addMeasuredRun (a run already measured in Java, passed into native code) @@ -354,15 +365,15 @@ public class StaticLayout extends Layout { * After all paragraphs, call finish() to release expensive buffers. */ - private void setLocale(Locale locale) { - if (!locale.equals(mLocale)) { - nSetLocale(mNativePtr, locale.toLanguageTag(), - Hyphenator.get(locale).getNativePtr()); - mLocale = locale; + private void setLocales(LocaleList locales) { + if (!locales.equals(mLocales)) { + nSetLocales(mNativePtr, locales.toLanguageTags(), getHyphenators(locales)); + mLocales = locales; } } /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) { + setLocales(paint.getTextLocales()); return nAddStyleRun(mNativePtr, paint.getNativeInstance(), paint.mNativeTypeface, start, end, isRtl); } @@ -425,7 +436,7 @@ public class StaticLayout extends Layout { // This will go away and be subsumed by native builder code MeasuredText mMeasuredText; - Locale mLocale; + LocaleList mLocales; private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3); } @@ -594,7 +605,7 @@ public class StaticLayout extends Layout { // store fontMetrics per span range // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range) int[] fmCache = new int[4 * 4]; - b.setLocale(paint.getTextLocale()); // TODO: also respect LocaleSpan within the text + b.setLocales(paint.getTextLocales()); mLineCount = 0; @@ -1308,7 +1319,8 @@ public class StaticLayout extends Layout { /* package */ static native long nLoadHyphenator(ByteBuffer buf, int offset, int minPrefix, int minSuffix); - private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator); + private static native void nSetLocales(long nativePtr, String locales, + long[] nativeHyphenators); private static native void nSetIndents(long nativePtr, int[] indents); diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 2e8faeec6f13..0d676153b288 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -25,6 +25,7 @@ import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Handler; import android.util.AttributeSet; import android.util.Log; @@ -532,8 +533,14 @@ public class ListPopupWindow implements ShowableListMenu { public void setHeight(int height) { if (height < 0 && ViewGroup.LayoutParams.WRAP_CONTENT != height && ViewGroup.LayoutParams.MATCH_PARENT != height) { - throw new IllegalArgumentException( - "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT."); + if (mContext.getApplicationInfo().targetSdkVersion + < Build.VERSION_CODES.O) { + Log.e(TAG, "Negative value " + height + " passed to ListPopupWindow#setHeight" + + " produces undefined results"); + } else { + throw new IllegalArgumentException( + "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT."); + } } mDropDownHeight = height; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6b328ea01997..9a924890fcd7 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -913,7 +913,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextAppearance_fontFamily: - if (!context.isRestricted()) { + if (!context.isRestricted() && context.canLoadUnsafeResources()) { try { fontTypeface = appearance.getFont(attr); } catch (UnsupportedOperationException @@ -1233,7 +1233,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextView_fontFamily: - if (!context.isRestricted()) { + if (!context.isRestricted() && context.canLoadUnsafeResources()) { try { fontTypeface = a.getFont(attr); } catch (UnsupportedOperationException | Resources.NotFoundException e) { @@ -3417,7 +3417,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Typeface fontTypeface = null; String fontFamily = null; - if (!context.isRestricted()) { + if (!context.isRestricted() && context.canLoadUnsafeResources()) { try { fontTypeface = ta.getFont(R.styleable.TextAppearance_fontFamily); } catch (UnsupportedOperationException | Resources.NotFoundException e) { diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 1779ada24aac..e8f6074051cf 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -396,7 +396,7 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) } static void -android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source, +android_media_AudioSystem_recording_callback(int event, const record_client_info_t *clientInfo, const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig, audio_patch_handle_t patchHandle) { @@ -404,8 +404,8 @@ android_media_AudioSystem_recording_callback(int event, audio_session_t session, if (env == NULL) { return; } - if (clientConfig == NULL || deviceConfig == NULL) { - ALOGE("Unexpected null client/device configurations in recording callback"); + if (clientInfo == NULL || clientConfig == NULL || deviceConfig == NULL) { + ALOGE("Unexpected null client/device info or configurations in recording callback"); return; } @@ -433,7 +433,7 @@ android_media_AudioSystem_recording_callback(int event, audio_session_t session, jclass clazz = env->FindClass(kClassPathName); env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative, - event, session, source, recParamArray); + event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, recParamArray); env->DeleteLocalRef(clazz); env->DeleteLocalRef(recParamArray); @@ -1930,7 +1930,7 @@ int register_android_media_AudioSystem(JNIEnv *env) "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), - "recordingCallbackFromNative", "(III[I)V"); + "recordingCallbackFromNative", "(IIII[I)V"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp index 4a445d8705ca..d81bc2f05018 100644 --- a/core/jni/android_text_StaticLayout.cpp +++ b/core/jni/android_text_StaticLayout.cpp @@ -137,15 +137,19 @@ static jlong nLoadHyphenator(JNIEnv* env, jclass, jobject buffer, jint offset, return reinterpret_cast<jlong>(hyphenator); } -static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName, - jlong nativeHyphenator) { - ScopedIcuLocale icuLocale(env, javaLocaleName); +static void nSetLocales(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleNames, + jlongArray nativeHyphenators) { minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr); - minikin::Hyphenator* hyphenator = reinterpret_cast<minikin::Hyphenator*>(nativeHyphenator); - if (icuLocale.valid()) { - b->setLocale(icuLocale.locale(), hyphenator); + ScopedUtfChars localeNames(env, javaLocaleNames); + ScopedLongArrayRO hyphArr(env, nativeHyphenators); + const size_t numLocales = hyphArr.size(); + std::vector<minikin::Hyphenator*> hyphVec; + hyphVec.reserve(numLocales); + for (size_t i = 0; i < numLocales; i++) { + hyphVec.push_back(reinterpret_cast<minikin::Hyphenator*>(hyphArr[i])); } + b->setLocales(localeNames.c_str(), hyphVec); } static void nSetIndents(JNIEnv* env, jclass, jlong nativePtr, jintArray indents) { @@ -194,7 +198,7 @@ static const JNINativeMethod gMethods[] = { {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, {"nFinishBuilder", "(J)V", (void*) nFinishBuilder}, {"nLoadHyphenator", "(Ljava/nio/ByteBuffer;III)J", (void*) nLoadHyphenator}, - {"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale}, + {"nSetLocales", "(JLjava/lang/String;[J)V", (void*) nSetLocales}, {"nSetupParagraph", "(J[CIFIF[IIIIZ)V", (void*) nSetupParagraph}, {"nSetIndents", "(J[I)V", (void*) nSetIndents}, {"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun}, diff --git a/core/res/res/values-mcc302-mnc370/strings.xml b/core/res/res/values-mcc302-mnc370/strings.xml new file mode 100644 index 000000000000..f5b8496f9a0b --- /dev/null +++ b/core/res/res/values-mcc302-mnc370/strings.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Template for showing mobile network operator name while WFC is active --> + <string-array name="wfcSpnFormats"> + <item>%s</item> + <item>%s Wi-Fi</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc720/strings.xml b/core/res/res/values-mcc302-mnc720/strings.xml new file mode 100644 index 000000000000..f5b8496f9a0b --- /dev/null +++ b/core/res/res/values-mcc302-mnc720/strings.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Template for showing mobile network operator name while WFC is active --> + <string-array name="wfcSpnFormats"> + <item>%s</item> + <item>%s Wi-Fi</item> + </string-array> +</resources> diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java index a9357c9175ab..7f4819bf63a1 100644 --- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java +++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java @@ -107,7 +107,7 @@ public class RulesStateTest { "2016a", formatVersion(1, 1), true /* operationInProgress */, RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */, RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */); - checkParcelableRoundTrip(rulesStateWithNulls); + checkParcelableRoundTrip(rulesStateWithUnknowns); } private static void checkParcelableRoundTrip(RulesState rulesState) { @@ -121,55 +121,14 @@ public class RulesStateTest { } @Test - public void isSystemVersionOlderThan() { + public void isSystemVersionNewerThan() { RulesState rulesState = new RulesState( "2016b", formatVersion(1, 1), false /* operationInProgress */, RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */, RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3)); - assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016a", 1))); - assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016b", 1))); - assertTrue(rulesState.isSystemVersionOlderThan(rulesVersion("2016c", 1))); - } - - @Test - public void isInstalledDistroOlderThan() { - RulesState operationInProgress = new RulesState( - "2016b", formatVersion(1, 1), true /* operationInProgress */, - RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */, - RulesState.STAGED_OPERATION_UNKNOWN, null /* installedDistroRulesVersion */); - try { - operationInProgress.isInstalledDistroOlderThan(rulesVersion("2016b", 1)); - fail(); - } catch (IllegalStateException expected) { - } - - RulesState nothingInstalled = new RulesState( - "2016b", formatVersion(1, 1), false /* operationInProgress */, - RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */, - RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */); - try { - nothingInstalled.isInstalledDistroOlderThan(rulesVersion("2016b", 1)); - fail(); - } catch (IllegalStateException expected) { - } - - DistroRulesVersion installedVersion = rulesVersion("2016b", 3); - RulesState rulesStateWithInstalledVersion = new RulesState( - "2016b", formatVersion(1, 1), false /* operationInProgress */, - RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */, - RulesState.DISTRO_STATUS_INSTALLED, installedVersion); - - DistroRulesVersion olderRules = rulesVersion("2016a", 1); - assertEquals(installedVersion.isOlderThan(olderRules), - rulesStateWithInstalledVersion.isInstalledDistroOlderThan(olderRules)); - - DistroRulesVersion sameRules = rulesVersion("2016b", 1); - assertEquals(installedVersion.isOlderThan(sameRules), - rulesStateWithInstalledVersion.isInstalledDistroOlderThan(sameRules)); - - DistroRulesVersion newerRules = rulesVersion("2016c", 1); - assertEquals(installedVersion.isOlderThan(newerRules), - rulesStateWithInstalledVersion.isInstalledDistroOlderThan(newerRules)); + assertTrue(rulesState.isSystemVersionNewerThan(rulesVersion("2016a", 1))); + assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016b", 1))); + assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016c", 1))); } private static void assertEqualsContract(RulesState one, RulesState two) { diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java index 74a6cc629937..fb60e38fcbf6 100644 --- a/core/tests/coretests/src/android/text/StaticLayoutTest.java +++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java @@ -22,10 +22,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.graphics.Paint.FontMetricsInt; +import android.os.LocaleList; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.Layout.Alignment; import android.text.method.EditorState; +import android.text.style.LocaleSpan; import android.util.Log; import org.junit.Before; @@ -35,6 +37,7 @@ import org.junit.runner.RunWith; import java.text.Normalizer; import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * Tests StaticLayout vertical metrics behavior. @@ -671,4 +674,76 @@ public class StaticLayoutTest { assertEquals(testLabel, 4, layout.getOffsetToRightOf(5)); } } + + @Test + public void testLocaleSpanAffectsHyphenation() { + TextPaint paint = new TextPaint(); + paint.setTextLocale(Locale.US); + // Private use language, with no hyphenation rules. + final Locale privateLocale = Locale.forLanguageTag("qaa"); + + final String longWord = "philanthropic"; + final float wordWidth = paint.measureText(longWord); + // Wide enough that words get hyphenated by default. + final int paraWidth = Math.round(wordWidth * 1.8f); + final String sentence = longWord + " " + longWord + " " + longWord + " " + longWord + " " + + longWord + " " + longWord; + + final int numEnglishLines = StaticLayout.Builder + .obtain(sentence, 0, sentence.length(), paint, paraWidth) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL) + .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) + .build() + .getLineCount(); + + { + final SpannableString text = new SpannableString(sentence); + text.setSpan(new LocaleSpan(privateLocale), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + final int numPrivateLocaleLines = StaticLayout.Builder + .obtain(text, 0, text.length(), paint, paraWidth) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL) + .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) + .build() + .getLineCount(); + + // Since the paragraph set to English gets hyphenated, the number of lines would be + // smaller than the number of lines when there is a span setting a language that + // doesn't get hyphenated. + assertTrue(numEnglishLines < numPrivateLocaleLines); + } + { + // Same as the above test, except that the locale span now uses a locale list starting + // with the private non-hyphenating locale. + final SpannableString text = new SpannableString(sentence); + final LocaleList locales = new LocaleList(privateLocale, Locale.US); + text.setSpan(new LocaleSpan(locales), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + final int numPrivateLocaleLines = StaticLayout.Builder + .obtain(text, 0, text.length(), paint, paraWidth) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL) + .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) + .build() + .getLineCount(); + + assertTrue(numEnglishLines < numPrivateLocaleLines); + } + { + final SpannableString text = new SpannableString(sentence); + // Apply the private LocaleSpan only to the first word, which is not getting hyphenated + // anyway. + text.setSpan(new LocaleSpan(privateLocale), 0, longWord.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + final int numPrivateLocaleLines = StaticLayout.Builder + .obtain(text, 0, text.length(), paint, paraWidth) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL) + .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) + .build() + .getLineCount(); + + // Since the first word is not hyphenated anyway (there's enough width), the LocaleSpan + // should not affect the layout. + assertEquals(numEnglishLines, numPrivateLocaleLines); + } + } } diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 81cc93da2e6f..93fc3da54550 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -267,6 +267,42 @@ public final class AudioFormat implements Parcelable { **/ public static final int ENCODING_DOLBY_TRUEHD = 14; + /** @hide */ + public static String toLogFriendlyEncoding(int enc) { + switch(enc) { + case ENCODING_INVALID: + return "ENCODING_INVALID"; + case ENCODING_PCM_16BIT: + return "ENCODING_PCM_16BIT"; + case ENCODING_PCM_8BIT: + return "ENCODING_PCM_8BIT"; + case ENCODING_PCM_FLOAT: + return "ENCODING_PCM_FLOAT"; + case ENCODING_AC3: + return "ENCODING_AC3"; + case ENCODING_E_AC3: + return "ENCODING_E_AC3"; + case ENCODING_DTS: + return "ENCODING_DTS"; + case ENCODING_DTS_HD: + return "ENCODING_DTS_HD"; + case ENCODING_MP3: + return "ENCODING_MP3"; + case ENCODING_AAC_LC: + return "ENCODING_AAC_LC"; + case ENCODING_AAC_HE_V1: + return "ENCODING_AAC_HE_V1"; + case ENCODING_AAC_HE_V2: + return "ENCODING_AAC_HE_V2"; + case ENCODING_IEC61937: + return "ENCODING_IEC61937"; + case ENCODING_DOLBY_TRUEHD: + return "ENCODING_DOLBY_TRUEHD"; + default : + return "invalid encoding " + enc; + } + } + /** Invalid audio channel configuration */ /** @deprecated Use {@link #CHANNEL_INVALID} instead. */ @Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0; @@ -693,6 +729,12 @@ public final class AudioFormat implements Parcelable { return mPropertySetMask; } + /** @hide */ + public String toLogFriendlyString() { + return String.format("%dch %dHz %s", + getChannelCount(), mSampleRate, toLogFriendlyEncoding(mEncoding)); + } + /** * Builder class for {@link AudioFormat} objects. * Use this class to configure and create an AudioFormat instance. By setting format diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java index 50dbd035b84d..984c5542cb7b 100644 --- a/media/java/android/media/AudioRecordingConfiguration.java +++ b/media/java/android/media/AudioRecordingConfiguration.java @@ -17,10 +17,12 @@ package android.media; import android.annotation.IntDef; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -52,18 +54,59 @@ public final class AudioRecordingConfiguration implements Parcelable { private final AudioFormat mDeviceFormat; private final AudioFormat mClientFormat; + @NonNull private final String mClientPackageName; + private final int mClientUid; + private final int mPatchHandle; /** * @hide */ - public AudioRecordingConfiguration(int session, int source, AudioFormat clientFormat, - AudioFormat devFormat, int patchHandle) { + public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, + AudioFormat devFormat, int patchHandle, String packageName) { + mClientUid = uid; mSessionId = session; mClientSource = source; mClientFormat = clientFormat; mDeviceFormat = devFormat; mPatchHandle = patchHandle; + mClientPackageName = packageName; + } + + /** + * @hide + * For AudioService dump + * @param pw + */ + public void dump(PrintWriter pw) { + pw.println(" " + toLogFriendlyString(this)); + } + + /** + * @hide + */ + public static String toLogFriendlyString(AudioRecordingConfiguration arc) { + return new String("session:" + arc.mSessionId + + " -- source:" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource) + + " -- uid:" + arc.mClientUid + + " -- patch:" + arc.mPatchHandle + + " -- pack:" + arc.mClientPackageName + + " -- format client=" + arc.mClientFormat.toLogFriendlyString() + + ", dev=" + arc.mDeviceFormat.toLogFriendlyString()); + } + + // Note that this method is called server side, so no "privileged" information is ever sent + // to a client that is not supposed to have access to it. + /** + * @hide + * Creates a copy of the recording configuration that is stripped of any data enabling + * identification of which application it is associated with ("anonymized"). + * @param in + */ + public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) { + return new AudioRecordingConfiguration( /*anonymized uid*/ -1, + in.mSessionId, in.mClientSource, in.mClientFormat, + in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/); } // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source) @@ -120,6 +163,30 @@ public final class AudioRecordingConfiguration implements Parcelable { public AudioFormat getClientFormat() { return mClientFormat; } /** + * @pending for SystemApi + * Returns the package name of the application performing the recording. + * Where there are multiple packages sharing the same user id through the "sharedUserId" + * mechanism, only the first one with that id will be returned + * (see {@link PackageManager#getPackagesForUid(int)}). + * <p>This information is only available if the caller has the + * {@link android.Manifest.permission.MODIFY_AUDIO_ROUTING} permission. + * <br>When called without the permission, the result is an empty string. + * @return the package name + */ + public String getClientPackageName() { return mClientPackageName; } + + /** + * @pending for SystemApi + * Returns the user id of the application performing the recording. + * <p>This information is only available if the caller has the + * {@link android.Manifest.permission.MODIFY_AUDIO_ROUTING} + * permission. + * <br>The result is -1 without the permission. + * @return the user id + */ + public int getClientUid() { return mClientUid; } + + /** * Returns information about the audio input device used for this recording. * @return the audio recording device or null if this information cannot be retrieved */ @@ -185,6 +252,8 @@ public final class AudioRecordingConfiguration implements Parcelable { mClientFormat.writeToParcel(dest, 0); mDeviceFormat.writeToParcel(dest, 0); dest.writeInt(mPatchHandle); + dest.writeString(mClientPackageName); + dest.writeInt(mClientUid); } private AudioRecordingConfiguration(Parcel in) { @@ -193,6 +262,8 @@ public final class AudioRecordingConfiguration implements Parcelable { mClientFormat = AudioFormat.CREATOR.createFromParcel(in); mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in); mPatchHandle = in.readInt(); + mClientPackageName = in.readString(); + mClientUid = in.readInt(); } @Override @@ -202,10 +273,12 @@ public final class AudioRecordingConfiguration implements Parcelable { AudioRecordingConfiguration that = (AudioRecordingConfiguration) o; - return ((mSessionId == that.mSessionId) + return ((mClientUid == that.mClientUid) + && (mSessionId == that.mSessionId) && (mClientSource == that.mClientSource) && (mPatchHandle == that.mPatchHandle) && (mClientFormat.equals(that.mClientFormat)) - && (mDeviceFormat.equals(that.mDeviceFormat))); + && (mDeviceFormat.equals(that.mDeviceFormat)) + && (mClientPackageName.equals(that.mClientPackageName))); } } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 6ef3091dcc70..c7c2dd8aedcd 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -287,6 +287,7 @@ public class AudioSystem /** * Callback for recording activity notifications events * @param event + * @param uid uid of the client app performing the recording * @param session * @param source * @param recordingFormat an array of ints containing respectively the client and device @@ -298,9 +299,10 @@ public class AudioSystem * 4: device channel mask * 5: device sample rate * 6: patch handle + * @param packName package name of the client app performing the recording. NOT SUPPORTED */ - void onRecordingConfigurationChanged(int event, int session, int source, - int[] recordingFormat); + void onRecordingConfigurationChanged(int event, int uid, int session, int source, + int[] recordingFormat, String packName); } private static AudioRecordingCallback sRecordingCallback; @@ -318,17 +320,18 @@ public class AudioSystem * @param session * @param source * @param recordingFormat see - * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])} for - * the description of the record format. + * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int[])} + * for the description of the record format. */ - private static void recordingCallbackFromNative(int event, int session, int source, + private static void recordingCallbackFromNative(int event, int uid, int session, int source, int[] recordingFormat) { AudioRecordingCallback cb = null; synchronized (AudioSystem.class) { cb = sRecordingCallback; } if (cb != null) { - cb.onRecordingConfigurationChanged(event, session, source, recordingFormat); + // TODO receive package name from native + cb.onRecordingConfigurationChanged(event, uid, session, source, recordingFormat, ""); } } diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 33a7c836dec8..59a124fa434f 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -324,6 +324,40 @@ public class MediaRecorder } } + /** @hide */ + public static final String toLogFriendlyAudioSource(int source) { + switch(source) { + case AudioSource.DEFAULT: + return "DEFAULT"; + case AudioSource.MIC: + return "MIC"; + case AudioSource.VOICE_UPLINK: + return "VOICE_UPLINK"; + case AudioSource.VOICE_DOWNLINK: + return "VOICE_DOWNLINK"; + case AudioSource.VOICE_CALL: + return "VOICE_CALL"; + case AudioSource.CAMCORDER: + return "CAMCORDER"; + case AudioSource.VOICE_RECOGNITION: + return "VOICE_RECOGNITION"; + case AudioSource.VOICE_COMMUNICATION: + return "VOICE_COMMUNICATION"; + case AudioSource.REMOTE_SUBMIX: + return "REMOTE_SUBMIX"; + case AudioSource.UNPROCESSED: + return "UNPROCESSED"; + case AudioSource.RADIO_TUNER: + return "RADIO_TUNER"; + case AudioSource.HOTWORD: + return "HOTWORD"; + case AudioSource.AUDIO_SOURCE_INVALID: + return "AUDIO_SOURCE_INVALID"; + default: + return "unknown source " + source; + } + } + /** * Defines the video source. These constants are used with * {@link MediaRecorder#setVideoSource(int)}. diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java index 5a1e603e7fa2..f1d43bfe4096 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java @@ -51,6 +51,12 @@ public class Tile implements Parcelable { public Icon icon; /** + * Whether the icon can be tinted. This should be set to true for monochrome (single-color) + * icons that can be tinted to match the design. + */ + public boolean isIconTintable; + + /** * Intent to launch when the preference is selected. */ public Intent intent; @@ -126,6 +132,7 @@ public class Tile implements Parcelable { dest.writeBundle(metaData); dest.writeString(key); dest.writeParcelable(remoteViews, flags); + dest.writeBoolean(isIconTintable); } public void readFromParcel(Parcel in) { @@ -147,6 +154,7 @@ public class Tile implements Parcelable { metaData = in.readBundle(); key = in.readString(); remoteViews = in.readParcelable(RemoteViews.class.getClassLoader()); + isIconTintable = in.readBoolean(); } Tile(Parcel in) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index 04a3d1f81561..9620a9153f80 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java @@ -133,15 +133,25 @@ public class TileUtils { /** * Name of the meta-data item that should be set in the AndroidManifest.xml - * to specify the title that should be displayed for the preference. + * to specify whether the icon is tintable. This should be a boolean value {@code true} or + * {@code false}, set using {@code android:value} */ - @Deprecated - public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; + public static final String META_DATA_PREFERENCE_ICON_TINTABLE = + "com.android.settings.icon_tintable"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the title that should be displayed for the preference. + * + * <p>Note: It is preferred to provide this value using {@code android:resource} with a string + * resource for localization. + */ + public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; + + /** + * @deprecated Use {@link #META_DATA_PREFERENCE_TITLE} with {@code android:resource} */ + @Deprecated public static final String META_DATA_PREFERENCE_TITLE_RES_ID = "com.android.settings.title.resid"; @@ -309,12 +319,13 @@ public class TileUtils { intent.setPackage(settingPkg); } getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles, - usePriority, true); + usePriority, true, true); } - public static void getTilesForIntent(Context context, UserHandle user, Intent intent, + public static void getTilesForIntent( + Context context, UserHandle user, Intent intent, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, - boolean usePriority, boolean checkCategory) { + boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) { PackageManager pm = context.getPackageManager(); List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, user.getIdentifier()); @@ -350,7 +361,7 @@ public class TileUtils { tile.priority = usePriority ? resolved.priority : 0; tile.metaData = activityInfo.metaData; updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, - pm, providerMap); + pm, providerMap, forceTintExternalIcon); if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title); addedCache.put(key, tile); @@ -366,25 +377,40 @@ public class TileUtils { private static boolean updateTileData(Context context, Tile tile, ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm, - Map<String, IContentProvider> providerMap) { + Map<String, IContentProvider> providerMap, boolean forceTintExternalIcon) { if (applicationInfo.isSystemApp()) { + boolean forceTintIcon = false; int icon = 0; Pair<String, Integer> iconFromUri = null; CharSequence title = null; String summary = null; String keyHint = null; + boolean isIconTintable = false; RemoteViews remoteViews = null; // Get the activity's meta-data try { - Resources res = pm.getResourcesForApplication( - applicationInfo.packageName); + Resources res = pm.getResourcesForApplication(applicationInfo.packageName); Bundle metaData = activityInfo.metaData; + if (forceTintExternalIcon + && !context.getPackageName().equals(applicationInfo.packageName)) { + isIconTintable = true; + forceTintIcon = true; + } + if (res != null && metaData != null) { if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { icon = metaData.getInt(META_DATA_PREFERENCE_ICON); } + if (metaData.containsKey(META_DATA_PREFERENCE_ICON_TINTABLE)) { + if (forceTintIcon) { + Log.w(LOG_TAG, "Ignoring icon tintable for " + activityInfo); + } else { + isIconTintable = + metaData.getBoolean(META_DATA_PREFERENCE_ICON_TINTABLE); + } + } int resId = 0; if (metaData.containsKey(META_DATA_PREFERENCE_TITLE_RES_ID)) { resId = metaData.getInt(META_DATA_PREFERENCE_TITLE_RES_ID); @@ -392,8 +418,6 @@ public class TileUtils { title = res.getString(resId); } } - // Fallback to legacy title extraction if we couldn't get the title through - // res id. if ((resId == 0) && metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) { title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); @@ -457,6 +481,7 @@ public class TileUtils { activityInfo.name); // Suggest a key for this tile tile.key = keyHint; + tile.isIconTintable = isIconTintable; tile.remoteViews = remoteViews; return true; diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java index a28bece100eb..167ffe61e42b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java @@ -208,7 +208,7 @@ public class SuggestionParser { intent.setPackage(category.pkg); } TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent, - mAddCache, null, suggestions, true, false); + mAddCache, null, suggestions, true, false, false); filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled); if (!category.multiple && suggestions.size() > (countBefore + 1)) { // If there are too many, remove them all and only re-add the one with the highest diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java index a3345ee58b7d..0ec75ecee066 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java @@ -36,6 +36,8 @@ import static junit.framework.Assert.assertTrue; public class ZoneGetterTest { private static final String TIME_ZONE_LONDON_ID = "Europe/London"; private static final String TIME_ZONE_LA_ID = "America/Los_Angeles"; + private static final String TIME_ZONE_ALGIERS_ID = "Africa/Algiers"; + private static final String TIME_ZONE_CEUTA_ID = "Africa/Ceuta"; private Locale mLocaleEnUs; private Calendar mCalendar; @@ -59,6 +61,16 @@ public class ZoneGetterTest { } @Test + public void getTimeZoneOffsetAndName_setAlgiers_returnCentralEuropeanStandardTime() { + testTimeZoneOffsetAndNameInner(TIME_ZONE_ALGIERS_ID, "Central European Standard Time"); + } + + @Test + public void getTimeZoneOffsetAndName_setCeuta_returnCentralEuropeanSummerTime() { + testTimeZoneOffsetAndNameInner(TIME_ZONE_CEUTA_ID, "Central European Summer Time"); + } + + @Test public void getZonesList_checkTypes() { final List<Map<String, Object>> zones = ZoneGetter.getZonesList(InstrumentationRegistry.getContext()); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java index 22fd83c67667..31abecda9a39 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java @@ -19,5 +19,5 @@ package com.android.settingslib; public class TestConfig { public static final int SDK_VERSION = 23; public static final String MANIFEST_PATH = - "frameworks/base/packages/SettingsLib/robotests/AndroidManifest.xml"; + "frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml"; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 7cfb32d7bdb0..036441839b5b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -16,6 +16,19 @@ package com.android.settingslib.drawer; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.RuntimeEnvironment.application; + import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; @@ -50,8 +63,9 @@ import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; import org.robolectric.internal.ShadowExtractor; import java.util.ArrayList; @@ -59,20 +73,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - @RunWith(RobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, @@ -100,8 +100,11 @@ public class TileUtilsTest { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources); - mContentResolver = spy(RuntimeEnvironment.application.getContentResolver()); + when(mPackageManager.getApplicationInfo(eq("abc"), anyInt())) + .thenReturn(application.getApplicationInfo()); + mContentResolver = spy(application.getContentResolver()); when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getPackageName()).thenReturn("com.android.settings"); } @Test @@ -118,7 +121,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).category).isEqualTo(testCategory); @@ -139,7 +142,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).key).isEqualTo(keyHint); @@ -159,7 +162,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.isEmpty()).isTrue(); } @@ -182,7 +185,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); SuggestionParser parser = new SuggestionParser( @@ -255,7 +258,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).title).isEqualTo("my title"); @@ -279,10 +282,60 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).title).isEqualTo("my localized title"); + + // Icon should be tintable because the tile is not from settings package, and + // "forceTintExternalIcon" is set + assertThat(outTiles.get(0).isIconTintable).isTrue(); + } + + @Test + public void getTilesForIntent_shouldNotTintIconIfInSettingsPackage() { + Intent intent = new Intent(); + Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); + List<Tile> outTiles = new ArrayList<>(); + List<ResolveInfo> info = new ArrayList<>(); + ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, + URI_GET_SUMMARY, null, 123); + resolveInfo.activityInfo.packageName = "com.android.settings"; + resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings"; + info.add(resolveInfo); + + when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + .thenReturn(info); + + TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + null /* defaultCategory */, outTiles, false /* usePriority */, + false /* checkCategory */, true /* forceTintExternalIcon */); + + assertThat(outTiles.size()).isEqualTo(1); + assertThat(outTiles.get(0).isIconTintable).isFalse(); + } + + @Test + public void getTilesForIntent_shouldMarkIconTintableIfMetadataSet() { + Intent intent = new Intent(); + Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); + List<Tile> outTiles = new ArrayList<>(); + List<ResolveInfo> info = new ArrayList<>(); + ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, + URI_GET_SUMMARY, null, 123); + resolveInfo.activityInfo.metaData + .putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true); + info.add(resolveInfo); + + when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt())) + .thenReturn(info); + + TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, + null /* defaultCategory */, outTiles, false /* usePriority */, + false /* checkCategory */, false /* forceTintExternalIcon */); + + assertThat(outTiles.size()).isEqualTo(1); + assertThat(outTiles.get(0).isIconTintable).isTrue(); } @Test @@ -301,7 +354,7 @@ public class TileUtilsTest { // Case 1: No provider associated with the uri specified. TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); @@ -319,7 +372,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); assertThat(outTiles.get(0).icon.getResId()).isEqualTo(314159); @@ -341,7 +394,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); } @@ -362,7 +415,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); @@ -399,7 +452,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); @@ -437,7 +490,7 @@ public class TileUtilsTest { TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */, - false /* checkCategory */); + false /* checkCategory */, true /* forceTintExternalIcon */); assertThat(outTiles.size()).isEqualTo(1); Tile tile = outTiles.get(0); @@ -484,7 +537,9 @@ public class TileUtilsTest { if (summaryUri != null) { info.activityInfo.metaData.putString("com.android.settings.summary_uri", summaryUri); } - if (title != null) { + if (titleResId != 0) { + info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title); + } else if (title != null) { info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title); } if (titleResId != 0) { diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java index 81bc83134b21..d9719f356f14 100644 --- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java +++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java @@ -101,7 +101,7 @@ public class Tonal implements ExtractionType { hsl[0] /= 360f; // Find the palette that contains the closest color - TonalPalette palette = findTonalPalette(hsl[0]); + TonalPalette palette = findTonalPalette(hsl[0], hsl[1]); if (palette == null) { Log.w(TAG, "Could not find a tonal palette!"); return false; @@ -251,7 +251,13 @@ public class Tonal implements ExtractionType { } @Nullable - private static TonalPalette findTonalPalette(float h) { + private static TonalPalette findTonalPalette(float h, float s) { + // Fallback to a grey palette if the color is too desaturated. + // This avoids hue shifts. + if (s < 0.05f) { + return GREY_PALETTE; + } + TonalPalette best = null; float error = Float.POSITIVE_INFINITY; @@ -327,271 +333,280 @@ public class Tonal implements ExtractionType { // a best fit. Each palette is defined as 22 HSL colors private static final TonalPalette[] TONAL_PALETTES = { new TonalPalette( - new float[]{0.991f, 0.9833333333333333f, 0f, 0f, 0f, 0.01134380453752181f, - 0.015625000000000003f, 0.024193548387096798f, 0.027397260273972573f, - 0.017543859649122865f}, - new float[]{1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.2f, 0.27450980392156865f, 0.34901960784313724f, - 0.4235294117647059f, 0.5490196078431373f, 0.6254901960784314f, - 0.6862745098039216f, 0.7568627450980392f, 0.8568627450980393f, - 0.9254901960784314f} + new float[] {1f, 1f, 0.991f, 0.991f, 0.9833333333333333f, 0f, 0f, 0f, + 0.01134380453752181f, 0.015625000000000003f, 0.024193548387096798f, + 0.027397260273972573f, 0.017543859649122865f}, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f, + 1f}, + new float[] {0.04f, 0.09f, 0.14f, 0.2f, 0.27450980392156865f, + 0.34901960784313724f, 0.4235294117647059f, 0.5490196078431373f, + 0.6254901960784314f, 0.6862745098039216f, 0.7568627450980392f, + 0.8568627450980393f, 0.9254901960784314f} ), new TonalPalette( - new float[]{0.6385767790262171f, 0.6301169590643275f, 0.6223958333333334f, - 0.6151079136690647f, 0.6065400843881856f, 0.5986964618249534f, - 0.5910746812386157f, 0.5833333333333334f, 0.5748031496062993f, - 0.5582010582010583f}, - new float[]{1f, 1f, 0.9014084507042253f, 0.8128654970760234f, - 0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, - 1f, 1f, 1f}, - new float[]{0.17450980392156862f, 0.2235294117647059f, 0.2784313725490196f, - 0.3352941176470588f, 0.388235294117647f, 0.44901960784313727f, - 0.5392156862745098f, 0.6509803921568628f, 0.7509803921568627f, - 0.8764705882352941f} + new float[] {0.638f, 0.638f, 0.6385767790262171f, 0.6301169590643275f, + 0.6223958333333334f, 0.6151079136690647f, 0.6065400843881856f, + 0.5986964618249534f, 0.5910746812386157f, 0.5833333333333334f, + 0.5748031496062993f, 0.5582010582010583f}, + new float[] {1f, 1f, 1f, 1f, 0.9014084507042253f, 0.8128654970760234f, + 0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, 1f, 1f, + 1f}, + new float[] {0.05f, 0.12f, 0.17450980392156862f, 0.2235294117647059f, + 0.2784313725490196f, 0.3352941176470588f, 0.388235294117647f, + 0.44901960784313727f, 0.5392156862745098f, 0.6509803921568628f, + 0.7509803921568627f, 0.8764705882352941f} ), new TonalPalette( - new float[]{0.5669934640522876f, 0.5748031496062993f, + new float[] {0.563f, 0.569f, 0.5666f, 0.5669934640522876f, 0.5748031496062993f, 0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f, 0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f, 0.508080808080808f, 0.5f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f, 1f}, - new float[]{0.2f, 0.24901960784313726f, 0.27450980392156865f, - 0.30392156862745096f, 0.34901960784313724f, 0.4137254901960784f, - 0.47647058823529415f, 0.5352941176470588f, 0.6764705882352942f, 0.8f} + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f, + 1f}, + new float[] {0.07f, 0.12f, 0.16f, 0.2f, 0.24901960784313726f, + 0.27450980392156865f, 0.30392156862745096f, 0.34901960784313724f, + 0.4137254901960784f, 0.47647058823529415f, 0.5352941176470588f, + 0.6764705882352942f, 0.8f} ), new TonalPalette( - new float[]{0.5082304526748972f, 0.5069444444444444f, 0.5f, 0.5f, - 0.5f, 0.48724954462659376f, 0.4800347222222222f, - 0.4755134281200632f, 0.4724409448818897f, 0.4671052631578947f}, - new float[]{1f, 0.8888888888888887f, 0.9242424242424242f, 1f, 1f, - 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f}, - new float[]{0.1588235294117647f, 0.21176470588235297f, - 0.25882352941176473f, 0.3f, 0.34901960784313724f, + new float[] {0.508f, 0.511f, 0.508f, 0.508f, 0.5082304526748972f, + 0.5069444444444444f, 0.5f, 0.5f, 0.5f, 0.48724954462659376f, + 0.4800347222222222f, 0.4755134281200632f, 0.4724409448818897f, + 0.4671052631578947f}, + new float[] {1f, 1f, 1f, 1f, 1f, 0.8888888888888887f, 0.9242424242424242f, 1f, + 1f, 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f}, + new float[] {0.04f, 0.06f, 0.08f, 0.12f, 0.1588235294117647f, + 0.21176470588235297f, 0.25882352941176473f, 0.3f, 0.34901960784313724f, 0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f, 0.7509803921568627f, 0.8509803921568627f} ), new TonalPalette( - new float[]{0.3333333333333333f, 0.3333333333333333f, + new float[] {0.333f, 0.333f, 0.333f, 0.3333333333333333f, 0.3333333333333333f, 0.34006734006734f, 0.34006734006734f, 0.34006734006734f, 0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f, 0.3467741935483871f, 0.3703703703703704f}, - new float[]{0.6703296703296703f, 0.728813559322034f, + new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f, 0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f, 0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f}, - new float[]{0.1784313725490196f, 0.23137254901960785f, + new float[] {0.05f, 0.08f, 0.1784313725490196f, 0.23137254901960785f, 0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f, 0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f, 0.8784313725490196f, 0.9294117647058824f} ), new TonalPalette( - new float[]{0.162280701754386f, 0.15032679738562088f, + new float[] {0.161f, 0.163f, 0.163f, 0.162280701754386f, 0.15032679738562088f, 0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f, - 0.17824074074074076f, 0.18674698795180725f, - 0.18692449355432778f, 0.1946778711484594f, 0.18604651162790695f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.14901960784313725f, 0.2f, 0.24901960784313726f, - 0.30392156862745096f, 0.3784313725490196f, 0.4235294117647059f, - 0.48823529411764705f, 0.6450980392156863f, 0.7666666666666666f, - 0.8313725490196078f} + 0.17824074074074076f, 0.18674698795180725f, 0.18692449355432778f, + 0.1946778711484594f, 0.18604651162790695f}, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, + new float[] {0.05f, 0.08f, 0.11f, 0.14901960784313725f, 0.2f, + 0.24901960784313726f, 0.30392156862745096f, 0.3784313725490196f, + 0.4235294117647059f, 0.48823529411764705f, 0.6450980392156863f, + 0.7666666666666666f, 0.8313725490196078f} ), new TonalPalette( - new float[]{0.10619469026548674f, 0.11924686192468618f, - 0.13046448087431692f, 0.14248366013071895f, 0.1506024096385542f, - 0.16220238095238093f, 0.16666666666666666f, + new float[] {0.108f, 0.105f, 0.105f, 0.105f, 0.10619469026548674f, + 0.11924686192468618f, 0.13046448087431692f, 0.14248366013071895f, + 0.1506024096385542f, 0.16220238095238093f, 0.16666666666666666f, 0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.44313725490196076f, 0.46862745098039216f, - 0.47843137254901963f, 0.5f, 0.5117647058823529f, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, + new float[] {0.17f, 0.22f, 0.28f, 0.35f, 0.44313725490196076f, + 0.46862745098039216f, 0.47843137254901963f, 0.5f, 0.5117647058823529f, 0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f, 0.8509803921568627f, 0.9f} ), new TonalPalette( - new float[]{0.03561253561253561f, 0.05098039215686275f, - 0.07516339869281045f, 0.09477124183006536f, 0.1150326797385621f, - 0.134640522875817f, 0.14640522875816991f, 0.1582397003745319f, - 0.15773809523809523f, 0.15359477124183002f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.4588235294117647f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, - 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f} + new float[] {0.036f, 0.036f, 0.036f, 0.036f, 0.03561253561253561f, + 0.05098039215686275f, 0.07516339869281045f, 0.09477124183006536f, + 0.1150326797385621f, 0.134640522875817f, 0.14640522875816991f, + 0.1582397003745319f, 0.15773809523809523f, 0.15359477124183002f}, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, + new float[] {0.19f, 0.26f, 0.34f, 0.39f, 0.4588235294117647f, 0.5f, 0.5f, 0.5f, + 0.5f, 0.5f, 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f} ), new TonalPalette( - new float[]{0.9596491228070175f, 0.9593837535014005f, + new float[] {0.955f, 0.961f, 0.958f, 0.9596491228070175f, 0.9593837535014005f, 0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f, 0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f, 0.9754098360655739f, 0.9824561403508771f}, - new float[]{0.84070796460177f, 0.8206896551724138f, + new float[] {0.87f, 0.85f, 0.85f, 0.84070796460177f, 0.8206896551724138f, 0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.22156862745098038f, 0.2843137254901961f, + new float[] {0.06f, 0.11f, 0.16f, 0.22156862745098038f, 0.2843137254901961f, 0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f, 0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f, 0.9254901960784314f} ), new TonalPalette( - new float[]{0.841025641025641f, 0.8333333333333334f, + new float[] {0.866f, 0.855f, 0.841025641025641f, 0.8333333333333334f, 0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f, 0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f, 0.7771084337349398f, 0.7747747747747749f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f}, - new float[]{0.12745098039215685f, 0.15490196078431373f, + new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f, 0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f, - 0.36470588235294116f, 0.44901960784313727f, - 0.6568627450980392f, 0.7470588235294118f, 0.8450980392156863f} + 0.36470588235294116f, 0.44901960784313727f, 0.6568627450980392f, + 0.7470588235294118f, 0.8450980392156863f} ), new TonalPalette( - new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}, - new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}, - new float[]{0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f, - 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f, - 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f} - ), - new TonalPalette( - new float[]{0.955952380952381f, 0.9681069958847737f, - 0.9760479041916167f, 0.9873563218390804f, 0f, 0f, + new float[] {0.925f, 0.93f, 0.938f, 0.947f, 0.955952380952381f, + 0.9681069958847737f, 0.9760479041916167f, 0.9873563218390804f, 0f, 0f, 0.009057971014492771f, 0.026748971193415648f, 0.041666666666666616f, 0.05303030303030304f}, - new float[]{1f, 0.8350515463917526f, 0.6929460580912863f, + new float[] {1f, 1f, 1f, 1f, 1f, 0.8350515463917526f, 0.6929460580912863f, 0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f, 0.8070175438596495f, 0.9310344827586209f, 1f, 1f}, - new float[]{0.27450980392156865f, 0.3803921568627451f, - 0.4725490196078432f, 0.5549019607843138f, 0.6313725490196078f, - 0.707843137254902f, 0.7764705882352941f, 0.8294117647058823f, - 0.9058823529411765f, 0.9568627450980391f} + new float[] {0.10f, 0.13f, 0.17f, 0.2f, 0.27450980392156865f, + 0.3803921568627451f, 0.4725490196078432f, 0.5549019607843138f, + 0.6313725490196078f, 0.707843137254902f, 0.7764705882352941f, + 0.8294117647058823f, 0.9058823529411765f, 0.9568627450980391f} ), new TonalPalette( - new float[]{0.7514619883040936f, 0.7679738562091503f, + new float[] {0.733f, 0.736f, 0.744f, 0.7514619883040936f, 0.7679738562091503f, 0.7802083333333333f, 0.7844311377245509f, 0.796875f, 0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f, 0.8562091503267975f, 0.8666666666666667f}, - new float[]{1f, 1f, 0.8163265306122449f, 0.6653386454183268f, + new float[] {1f, 1f, 1f, 1f, 1f, 0.8163265306122449f, 0.6653386454183268f, 0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f, 0.9560439560439562f, 1f, 1f}, - new float[]{0.2235294117647059f, 0.3f, 0.38431372549019605f, - 0.492156862745098f, 0.5843137254901961f, 0.6647058823529411f, - 0.7333333333333334f, 0.8215686274509804f, 0.9f, + new float[] {0.07f, 0.12f, 0.17f, 0.2235294117647059f, 0.3f, + 0.38431372549019605f, 0.492156862745098f, 0.5843137254901961f, + 0.6647058823529411f, 0.7333333333333334f, 0.8215686274509804f, 0.9f, 0.9411764705882353f} ), new TonalPalette( - new float[]{0.6666666666666666f, 0.6666666666666666f, + new float[] {0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f}, - new float[]{0.24590163934426232f, 0.17880794701986752f, + new float[] {0.25f, 0.24590163934426232f, 0.17880794701986752f, 0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f, - 0.16756756756756758f, 0.20312500000000017f, - 0.26086956521739135f, 0.29999999999999966f, 0.5000000000000004f}, - new float[]{0.2392156862745098f, 0.296078431372549f, + 0.16756756756756758f, 0.20312500000000017f, 0.26086956521739135f, + 0.29999999999999966f, 0.5000000000000004f}, + new float[] {0.18f, 0.2392156862745098f, 0.296078431372549f, 0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f, 0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f, 0.8823529411764706f, 0.9372549019607843f} ), new TonalPalette( - new float[]{0.9678571428571429f, 0.9944812362030905f, 0f, 0f, + new float[] {0.938f, 0.944f, 0.952f, 0.961f, 0.9678571428571429f, + 0.9944812362030905f, 0f, 0f, 0.0047348484848484815f, 0.00316455696202532f, 0f, 0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f}, - new float[]{1f, 0.7023255813953488f, 0.6638655462184874f, + new float[] {1f, 1f, 1f, 1f, 1f, 0.7023255813953488f, 0.6638655462184874f, 0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f, 0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f, 0.8181818181818189f}, - new float[]{0.27450980392156865f, 0.4215686274509804f, + new float[] {0.08f, 0.13f, 0.18f, 0.23f, 0.27450980392156865f, + 0.4215686274509804f, 0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f, 0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f, 0.892156862745098f, 0.9568627450980391f} ), new TonalPalette( - new float[]{0.9052287581699346f, 0.9112021857923498f, 0.9270152505446624f, - 0.9343137254901961f, 0.9391534391534391f, 0.9437984496124031f, - 0.943661971830986f, 0.9438943894389439f, 0.9426229508196722f, - 0.9444444444444444f}, - new float[]{1f, 0.8133333333333332f, 0.7927461139896375f, 0.7798165137614679f, - 0.7777777777777779f, 0.8190476190476191f, 0.8255813953488372f, - 0.8211382113821142f, 0.8133333333333336f, 0.8000000000000006f}, - new float[]{0.2f, 0.29411764705882354f, 0.3784313725490196f, - 0.42745098039215684f, 0.4764705882352941f, 0.5882352941176471f, - 0.6627450980392157f, 0.7588235294117647f, 0.8529411764705882f, - 0.9411764705882353f} + new float[] {0.88f, 0.888f, 0.897f, 0.9052287581699346f, 0.9112021857923498f, + 0.9270152505446624f, 0.9343137254901961f, 0.9391534391534391f, + 0.9437984496124031f, 0.943661971830986f, 0.9438943894389439f, + 0.9426229508196722f, 0.9444444444444444f}, + new float[] {1f, 1f, 1f, 1f, 0.8133333333333332f, 0.7927461139896375f, + 0.7798165137614679f, 0.7777777777777779f, 0.8190476190476191f, + 0.8255813953488372f, 0.8211382113821142f, 0.8133333333333336f, + 0.8000000000000006f}, + new float[] {0.08f, 0.12f, 0.16f, 0.2f, 0.29411764705882354f, + 0.3784313725490196f, 0.42745098039215684f, 0.4764705882352941f, + 0.5882352941176471f, 0.6627450980392157f, 0.7588235294117647f, + 0.8529411764705882f, 0.9411764705882353f} ), new TonalPalette( - new float[]{0.6884057971014492f, 0.6974789915966387f, 0.7079889807162534f, - 0.7154471544715447f, 0.7217741935483872f, 0.7274143302180687f, - 0.7272727272727273f, 0.7258064516129031f, 0.7252252252252251f, - 0.7333333333333333f}, - new float[]{0.8214285714285715f, 0.6878612716763006f, 0.6080402010050251f, - 0.5774647887323943f, 0.5391304347826086f, 0.46724890829694316f, - 0.4680851063829788f, 0.462686567164179f, 0.45679012345678977f, - 0.4545454545454551f}, - new float[]{0.2196078431372549f, 0.33921568627450976f, 0.39019607843137255f, - 0.4176470588235294f, 0.45098039215686275f, + new float[] {0.669f, 0.680f, 0.6884057971014492f, 0.6974789915966387f, + 0.7079889807162534f, 0.7154471544715447f, 0.7217741935483872f, + 0.7274143302180687f, 0.7272727272727273f, 0.7258064516129031f, + 0.7252252252252251f, 0.7333333333333333f}, + new float[] {0.81f, 0.81f, 0.8214285714285715f, 0.6878612716763006f, + 0.6080402010050251f, 0.5774647887323943f, 0.5391304347826086f, + 0.46724890829694316f, 0.4680851063829788f, 0.462686567164179f, + 0.45679012345678977f, 0.4545454545454551f}, + new float[] {0.12f, 0.16f, 0.2196078431372549f, 0.33921568627450976f, + 0.39019607843137255f, 0.4176470588235294f, 0.45098039215686275f, 0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f, 0.8411764705882353f, 0.9352941176470588f} ), new TonalPalette( - new float[]{0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f, + new float[] {0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f, 0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f, 0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f, 0.6428571428571429f}, - new float[]{0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f, + new float[] {0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f, 0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f, - 0.44360902255639095f, - 0.4499999999999997f, 0.4375000000000006f}, - new float[]{0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f, + 0.44360902255639095f, 0.4499999999999997f, 0.4375000000000006f}, + new float[] {0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f, 0.40588235294117647f, 0.44705882352941173f, 0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f, 0.8431372549019608f, 0.9372549019607843f} ), new TonalPalette( - new float[]{0.46732026143790845f, 0.4718614718614719f, 0.4793650793650794f, - 0.48071625344352614f, 0.4829683698296837f, 0.484375f, - 0.4841269841269842f, 0.48444444444444457f, 0.48518518518518516f, - 0.4907407407407408f}, - new float[]{1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f, - 0.41899441340782106f, 0.4128440366972478f, - 0.4090909090909088f}, - new float[]{0.1f, 0.15098039215686274f, 0.20588235294117646f, + new float[] {0.469f, 0.46732026143790845f, 0.4718614718614719f, + 0.4793650793650794f, 0.48071625344352614f, 0.4829683698296837f, + 0.484375f, 0.4841269841269842f, 0.48444444444444457f, + 0.48518518518518516f, 0.4907407407407408f}, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f, + 0.41899441340782106f, 0.4128440366972478f, 0.4090909090909088f}, + new float[] {0.07f, 0.1f, 0.15098039215686274f, 0.20588235294117646f, 0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f, 0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f} ), new TonalPalette( - new float[]{0.5444444444444444f, 0.5555555555555556f, 0.5555555555555556f, - 0.553763440860215f, 0.5526315789473684f, 0.5555555555555556f, - 0.5555555555555555f, 0.5555555555555556f, 0.5512820512820514f, - 0.5666666666666667f}, - new float[]{0.24590163934426232f, 0.19148936170212766f, 0.1791044776119403f, - 0.18343195266272191f, 0.18446601941747576f, + new float[] {0.542f, 0.5444444444444444f, 0.5555555555555556f, + 0.5555555555555556f, 0.553763440860215f, 0.5526315789473684f, + 0.5555555555555556f, 0.5555555555555555f, 0.5555555555555556f, + 0.5512820512820514f, 0.5666666666666667f}, + new float[] {0.25f, 0.24590163934426232f, 0.19148936170212766f, + 0.1791044776119403f, 0.18343195266272191f, 0.18446601941747576f, 0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f, 0.15662650602409653f, 0.151515151515151f}, - new float[]{0.1196078431372549f, 0.1843137254901961f, 0.2627450980392157f, + new float[] {0.05f, 0.1196078431372549f, 0.1843137254901961f, + 0.2627450980392157f, 0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f, 0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f, 0.9352941176470588f} ), new TonalPalette( - new float[]{0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f, + new float[] {0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f, 0.03947368421052631f, 0.04166666666666668f, 0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f, 0.04444444444444459f, 0.05555555555555529f}, - new float[]{0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f, + new float[] {0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f, 0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f, 0.15315315315315312f, 0.15189873417721522f, 0.15789473684210534f, 0.15789473684210542f}, - new float[]{0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f, + new float[] {0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f, 0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f, 0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f, 0.9254901960784314f} ), new TonalPalette( - new float[]{0.050884955752212385f, 0.07254901960784313f, 0.0934640522875817f, + new float[] {0.027f, 0.03f, 0.038f, 0.044f, 0.050884955752212385f, + 0.07254901960784313f, 0.0934640522875817f, 0.10457516339869281f, 0.11699346405228758f, 0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f, 0.12500000000000003f, 0.12777777777777777f}, - new float[]{1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, - new float[]{0.44313725490196076f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5784313725490196f, + new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f}, + new float[] {0.25f, 0.3f, 0.35f, 0.4f, 0.44313725490196076f, 0.5f, 0.5f, 0.5f, + 0.5f, 0.5784313725490196f, 0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f, 0.9411764705882353f} ) }; + private static final TonalPalette GREY_PALETTE = new TonalPalette( + new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}, + new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}, + new float[]{0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f, + 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f, + 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f} + ); + @SuppressWarnings("WeakerAccess") @VisibleForTesting static final ColorRange[] BLACKLISTED_COLORS = new ColorRange[] { diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml index 1aa732f43286..62e495974623 100644 --- a/packages/SystemUI/res/color/qs_background_dark.xml +++ b/packages/SystemUI/res/color/qs_background_dark.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:alpha="0.93" - android:color="?android:attr/colorPrimaryDark"/> + android:color="?android:attr/colorBackgroundFloating"/> </selector> diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/packages/SystemUI/res/drawable/pip_icon.xml new file mode 100644 index 000000000000..bd92ccd2e6e3 --- /dev/null +++ b/packages/SystemUI/res/drawable/pip_icon.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="25" + android:viewportHeight="25"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml index 416583013e64..03bba53946da 100644 --- a/packages/SystemUI/res/drawable/qs_background_primary.xml +++ b/packages/SystemUI/res/drawable/qs_background_primary.xml @@ -15,6 +15,6 @@ --> <inset xmlns:android="http://schemas.android.com/apk/res/android"> <shape> - <solid android:color="?android:attr/colorBackgroundFloating"/> + <solid android:color="@color/qs_background_dark"/> </shape> </inset> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 90761994cde6..18ffd0fac417 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -16,12 +16,12 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/volume_dialog" - android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/volume_dialog_margin_bottom" - android:layout_gravity="center_vertical|end" + android:background="@drawable/volume_dialog_background" android:paddingTop="@dimen/volume_dialog_padding_top" - android:translationZ="8dp" > + android:translationZ="4dp" > <LinearLayout android:id="@+id/volume_dialog_content" @@ -57,7 +57,6 @@ android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="1" - android:visibility="gone" android:textAppearance="@style/TextAppearance.Volume.Header" /> <com.android.keyguard.AlphaOptimizedImageButton xmlns:android="http://schemas.android.com/apk/res/android" diff --git a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml b/packages/SystemUI/res/layout/volume_dialog_wrapped.xml deleted file mode 100644 index 57489fd5f8d1..000000000000 --- a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<com.android.systemui.HardwareUiLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginTop="@dimen/top_padding" - android:layout_marginBottom="@dimen/bottom_padding"> - - <include layout="@layout/volume_dialog"/> - -</com.android.systemui.HardwareUiLayout> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 81ca23082367..74b0702ce5f6 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -398,4 +398,8 @@ it has been expanded to reveal its children. --> <bool name="config_showGroupNotificationBgWhenExpanded">false</bool> + <!-- Whether to artificially interpret all signal strengths as + one bar higher than they actually are --> + <bool name="config_inflateSignalStrength">false</bool> + </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1b2de8d8ea08..93d2072e955c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -216,6 +216,8 @@ <!-- The width of the panel that holds the quick settings. --> <dimen name="qs_panel_width">@dimen/notification_panel_width</dimen> + <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen> + <!-- Gravity for the notification panel --> <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top --> @@ -800,7 +802,6 @@ <dimen name="hwui_edge_margin">16dp</dimen> - <dimen name="volume_dialog_panel_width">315dp</dimen> <dimen name="global_actions_panel_width">125dp</dimen> <dimen name="global_actions_top_padding">100dp</dimen> @@ -819,11 +820,14 @@ <dimen name="edge_margin">16dp</dimen> <dimen name="rounded_corner_radius">0dp</dimen> - <dimen name="rounded_corner_content_padding">0dp</dimen> + <dimen name="rounded_corner_content_padding">8dp</dimen> <!-- Intended corner radius when drawing the mobile signal --> <dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen> <!-- How far to inset the rounded edges --> <dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen> + <!-- Width of the hollow triangle for empty signal state --> + <dimen name="mobile_signal_empty_strokewidth">2dp</dimen> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java index 7af4a90e1a86..14e15ec5716d 100644 --- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java +++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java @@ -55,11 +55,17 @@ public class RoundedCorners extends SystemUI implements Tunable { public void start() { mRoundedDefault = mContext.getResources().getDimensionPixelSize( R.dimen.rounded_corner_radius); - if (mRoundedDefault == 0) { - // No rounded corners on this device. - return; + if (mRoundedDefault != 0) { + setupRounding(); } + int padding = mContext.getResources().getDimensionPixelSize( + R.dimen.rounded_corner_content_padding); + if (padding != 0) { + setupPadding(padding); + } + } + private void setupRounding() { mOverlay = LayoutInflater.from(mContext) .inflate(R.layout.rounded_corners, null); mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); @@ -82,10 +88,10 @@ public class RoundedCorners extends SystemUI implements Tunable { mDensity = metrics.density; Dependency.get(TunerService.class).addTunable(this, SIZE); + } + private void setupPadding(int padding) { // Add some padding to all the content near the edge of the screen. - int padding = mContext.getResources().getDimensionPixelSize( - R.dimen.rounded_corner_content_padding); StatusBar sb = getComponent(StatusBar.class); View statusBar = sb.getStatusBarWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 699fdef3180a..6777ea2ef877 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.RectF; import android.os.Handler; +import android.util.ArrayMap; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -37,8 +38,6 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.FlingAnimationUtils; -import java.util.HashMap; - public class SwipeHelper implements Gefingerpoken { static final String TAG = "com.android.systemui.SwipeHelper"; private static final boolean DEBUG = false; @@ -51,10 +50,10 @@ public class SwipeHelper implements Gefingerpoken { public static final int X = 0; public static final int Y = 1; - private float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec - private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms - private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms - private int MAX_DISMISS_VELOCITY = 4000; // dp/sec + private static final float SWIPE_ESCAPE_VELOCITY = 500f; // dp/sec + private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms + private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms + private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width @@ -65,13 +64,13 @@ public class SwipeHelper implements Gefingerpoken { private float mMinSwipeProgress = 0f; private float mMaxSwipeProgress = 1f; - private FlingAnimationUtils mFlingAnimationUtils; + private final FlingAnimationUtils mFlingAnimationUtils; private float mPagingTouchSlop; - private Callback mCallback; - private Handler mHandler; - private int mSwipeDirection; - private VelocityTracker mVelocityTracker; - private FalsingManager mFalsingManager; + private final Callback mCallback; + private final Handler mHandler; + private final int mSwipeDirection; + private final VelocityTracker mVelocityTracker; + private final FalsingManager mFalsingManager; private float mInitialTouchPos; private float mPerpendicularInitialTouchPos; @@ -86,16 +85,16 @@ public class SwipeHelper implements Gefingerpoken { private boolean mLongPressSent; private LongPressListener mLongPressListener; private Runnable mWatchLongPress; - private long mLongPressTimeout; + private final long mLongPressTimeout; final private int[] mTmpPos = new int[2]; - private int mFalsingThreshold; + private final int mFalsingThreshold; private boolean mTouchAboveFalsingThreshold; private boolean mDisableHwLayers; - private boolean mFadeDependingOnAmountSwiped; - private Context mContext; + private final boolean mFadeDependingOnAmountSwiped; + private final Context mContext; - private HashMap<View, Animator> mDismissPendingMap = new HashMap<>(); + private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>(); public SwipeHelper(int swipeDirection, Callback callback, Context context) { mContext = context; diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java index 880951036661..4ff10e975b1a 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java @@ -34,12 +34,14 @@ public class ExtensionFragmentListener<T extends FragmentBase> implements Consum private final FragmentHostManager mFragmentHostManager; private final String mTag; private final Extension<T> mExtension; + private final int mId; private String mOldClass; private ExtensionFragmentListener(View view, String tag, int id, Extension<T> extension) { mTag = tag; mFragmentHostManager = FragmentHostManager.get(view); mExtension = extension; + mId = id; mFragmentHostManager.getFragmentManager().beginTransaction() .replace(id, (Fragment) mExtension.get(), mTag) .commit(); @@ -49,7 +51,7 @@ public class ExtensionFragmentListener<T extends FragmentBase> implements Consum public void accept(T extension) { try { Fragment.class.cast(extension); - mFragmentHostManager.getExtensionManager().setCurrentExtension(mTag, + mFragmentHostManager.getExtensionManager().setCurrentExtension(mId, mTag, mOldClass, extension.getClass().getName(), mExtension.getContext()); mOldClass = extension.getClass().getName(); } catch (ClassCastException e) { diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 871f113ac95e..f8f364da089b 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -266,16 +266,14 @@ public class FragmentHostManager { class ExtensionFragmentManager { private final ArrayMap<String, Context> mExtensionLookup = new ArrayMap<>(); - public void setCurrentExtension(@NonNull String tag, @Nullable String oldClass, + public void setCurrentExtension(int id, @NonNull String tag, @Nullable String oldClass, @NonNull String currentClass, @Nullable Context context) { - Fragment fragment = getFragmentManager().findFragmentByTag(tag); if (oldClass != null) { mExtensionLookup.remove(oldClass); } mExtensionLookup.put(currentClass, context); getFragmentManager().beginTransaction() - .replace(((View) fragment.getView().getParent()).getId(), - instantiate(context, currentClass, null), tag) + .replace(id, instantiate(context, currentClass, null), tag) .commit(); reloadFragments(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java index 32b5862e2b6b..af2b7677dcad 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java @@ -38,6 +38,7 @@ import android.util.Log; import android.view.View; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.R; /** * Bouncer between work activities and the activity used to confirm credentials before unlocking @@ -83,6 +84,7 @@ public class WorkLockActivity extends Activity { // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with // redaction switched on. final View blankView = new View(this); + blankView.setContentDescription(getString(R.string.accessibility_desc_work_lock)); blankView.setBackgroundColor(getPrimaryColor()); setContentView(blankView); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 0373d77940d7..ebf4b5d83029 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -93,6 +93,7 @@ public class PipManager implements BasePipManager { ComponentName topPipActivity = PipUtils.getTopPinnedActivity(mContext, mActivityManager); mMenuController.hideMenu(); + mTouchHandler.onActivityUnpinned(topPipActivity); mNotificationController.onActivityUnpinned(topPipActivity); SystemServicesProxy.getInstance(mContext).setPipVisibility(topPipActivity != null); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index ddaeb04f8443..3682ae655f7c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -25,6 +25,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.IActivityManager; +import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.graphics.PointF; @@ -116,7 +117,7 @@ public class PipTouchHandler { }; // Behaviour states - private int mMenuState; + private int mMenuState = MENU_STATE_NONE; private boolean mIsMinimized; private boolean mIsImeShowing; private int mImeHeight; @@ -212,14 +213,15 @@ public class PipTouchHandler { } public void onActivityPinned() { - // Reset some states once we are pinned - mMenuState = MENU_STATE_NONE; + cleanUp(); + mShowPipMenuOnAnimationEnd = true; + } - if (mIsMinimized) { - setMinimizedStateInternal(false); + public void onActivityUnpinned(ComponentName topPipActivity) { + if (topPipActivity == null) { + // Clean up state after the last PiP activity is removed + cleanUp(); } - cleanUpDismissTarget(); - mShowPipMenuOnAnimationEnd = true; } public void onPinnedStackAnimationEnded() { @@ -729,6 +731,16 @@ public class PipTouchHandler { mDismissViewController.destroyDismissTarget(); } + /** + * Resets some states related to the touch handling. + */ + private void cleanUp() { + if (mIsMinimized) { + setMinimizedStateInternal(false); + } + cleanUpDismissTarget(); + } + public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java index f0745a0791ef..ac41b752020b 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java @@ -174,7 +174,7 @@ public class PipNotification { void onConfigurationChanged(Context context) { Resources res = context.getResources(); mDefaultTitle = res.getString(R.string.pip_notification_unknown_title); - mDefaultIconResId = R.drawable.pip_expand; + mDefaultIconResId = R.drawable.pip_icon; if (mNotified) { // update notification notifyPipNotification(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index e6c3520c4d62..81ec6a7c72a9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -141,7 +141,11 @@ public class CellularTile extends QSTileImpl<SignalState> { && mDataController.isMobileDataEnabled(); state.icon = new SignalIcon(cb.mobileSignalIconId); - state.state = Tile.STATE_ACTIVE; + if (cb.airplaneModeEnabled) { + state.state = Tile.STATE_INACTIVE; + } else { + state.state = Tile.STATE_ACTIVE; + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index dca4a8d3308a..9ca756c5431f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -878,7 +878,8 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC // Recents doesn't care about the wallpaper being visible or not, it always // wants to scrim with wallpaper colors mBackgroundScrim.setColors( - mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, true)); + mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, + ColorExtractor.TYPE_DARK, true)); } } @@ -886,7 +887,7 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC mColorExtractor.addOnColorsChangedListener(this); // Getting system scrim colors ignoring wallpaper visibility since it should never be grey. ColorExtractor.GradientColors systemColors = mColorExtractor.getColors( - WallpaperManager.FLAG_SYSTEM, true); + ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true); // We don't want to interpolate colors because we're defining the initial state. // Gradient should be set/ready when you open "Recents". mBackgroundScrim.setColors(systemColors, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 67ea25870a45..97e2f6d3e6f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -465,7 +465,8 @@ public class NotificationShelf extends ActivatableNotificationView implements || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) { iconState.hidden = true; } - int shelfColor = icon.getStaticDrawableColor(); + int backgroundColor = getBackgroundColorWithoutTint(); + int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor); if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) { int iconColor = row.getVisibleNotificationHeader().getOriginalIconColor(); shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 3c7ddb502145..1a47e4428e49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -35,6 +35,7 @@ import android.graphics.drawable.Icon; import android.os.Parcelable; import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import android.support.v4.graphics.ColorUtils; import android.text.TextUtils; import android.util.AttributeSet; import android.util.FloatProperty; @@ -46,6 +47,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.animation.Interpolator; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.util.NotificationColorUtil; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.notification.NotificationIconDozeHelper; @@ -127,6 +129,8 @@ public class StatusBarIconView extends AnimatedImageView { setColorInternal(newColor); }; private final NotificationIconDozeHelper mDozer; + private int mContrastedDrawableColor; + private int mCachedContrastBackgroundColor = NO_COLOR; public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) { this(context, slot, sbn, false); @@ -528,6 +532,7 @@ public class StatusBarIconView extends AnimatedImageView { public void setStaticDrawableColor(int color) { mDrawableColor = color; setColorInternal(color); + updateContrastedStaticColor(); mIconColor = color; mDozer.setColor(color); } @@ -580,6 +585,42 @@ public class StatusBarIconView extends AnimatedImageView { return mDrawableColor; } + /** + * A drawable color that passes GAR on a specific background. + * This value is cached. + * + * @param backgroundColor Background to test against. + * @return GAR safe version of {@link StatusBarIconView#getStaticDrawableColor()}. + */ + int getContrastedStaticDrawableColor(int backgroundColor) { + if (mCachedContrastBackgroundColor != backgroundColor) { + mCachedContrastBackgroundColor = backgroundColor; + updateContrastedStaticColor(); + } + return mContrastedDrawableColor; + } + + private void updateContrastedStaticColor() { + if (mCachedContrastBackgroundColor == NO_COLOR) { + return; + } + // We'll modify the color if it doesn't pass GAR + int contrastedColor = mDrawableColor; + if (!NotificationColorUtil.satisfiesTextContrast(mCachedContrastBackgroundColor, + contrastedColor)) { + float[] hsl = new float[3]; + ColorUtils.colorToHSL(mDrawableColor, hsl); + // This is basically a light grey, pushing the color will only distort it. + // Best thing to do in here is to fallback to the default color. + if (hsl[1] < 0.2f) { + contrastedColor = Notification.COLOR_DEFAULT; + } + contrastedColor = NotificationColorUtil.resolveContrastColor(mContext, + contrastedColor, mCachedContrastBackgroundColor); + } + mContrastedDrawableColor = contrastedColor; + } + public void setVisibleState(int state) { setVisibleState(state, true /* animate */, null /* endRunnable */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 9275358e78bd..419aefe3e9e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -81,9 +81,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private final SysuiColorExtractor mColorExtractor; private ColorExtractor.GradientColors mLockColors; - private ColorExtractor.GradientColors mLockColorsDark; private ColorExtractor.GradientColors mSystemColors; - private ColorExtractor.GradientColors mSystemColorsDark; private boolean mNeedsDrawableColorUpdate; protected float mScrimBehindAlpha; @@ -135,13 +133,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, - ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */); - mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, - ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */); - // Darker gradient for the top scrim (mScrimInFront) - mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, ColorExtractor.TYPE_DARK, true /* ignoreVisibility */); - mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, + mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_DARK, true /* ignoreVisibility */); mNeedsDrawableColorUpdate = true; @@ -311,13 +304,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mNeedsDrawableColorUpdate = false; if (mKeyguardShowing) { // Always animate color changes if we're seeing the keyguard - mScrimInFront.setColors(mLockColorsDark); + mScrimInFront.setColors(mLockColors); mScrimBehind.setColors(mLockColors); } else { // Only animate scrim color if the scrim view is actually visible boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0; boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0; - mScrimInFront.setColors(mSystemColorsDark, animateScrimInFront); + mScrimInFront.setColors(mSystemColors, animateScrimInFront); mScrimBehind.setColors(mSystemColors, animateScrimBehind); } } @@ -663,16 +656,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, public void onColorsChanged(ColorExtractor colorExtractor, int which) { if ((which & WallpaperManager.FLAG_LOCK) != 0) { mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, - ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */); - mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, ColorExtractor.TYPE_DARK, true /* ignoreVisibility */); mNeedsDrawableColorUpdate = true; scheduleUpdate(); } if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, - ColorExtractor.TYPE_NORMAL, mKeyguardShowing); - mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_DARK, mKeyguardShowing); mNeedsDrawableColorUpdate = true; scheduleUpdate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java index 083da518eba4..deea521b7c2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -21,13 +21,15 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Matrix; import android.graphics.Paint; -import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.Path.Direction; import android.graphics.Path.FillType; import android.graphics.Path.Op; +import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Handler; import android.util.LayoutDirection; @@ -63,6 +65,7 @@ public class SignalDrawable extends Drawable { private static final int STATE_EMPTY = 1; private static final int STATE_CUT = 2; private static final int STATE_CARRIER_CHANGE = 3; + private static final int STATE_AIRPLANE = 4; private static final long DOT_DELAY = 1000; @@ -97,6 +100,17 @@ public class SignalDrawable extends Drawable { // How far the circle defining the corners is inset from the edges private final float mAppliedCornerInset; + // The easiest way to understand this is as if we set Style.STROKE and draw the triangle, + // but that is only theoretically right. Instead, draw the triangle and clip out a smaller + // one inset by this amount. + private final float mEmptyStrokeWidth; + private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f); + private final float mEmptyDiagInset; // == mEmptyStrokeWidth * INV_TAN + + // Where the top and left points of the triangle would be if not for rounding + private final PointF mVirtualTop = new PointF(); + private final PointF mVirtualLeft = new PointF(); + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int mDarkModeBackgroundColor; @@ -106,6 +120,10 @@ public class SignalDrawable extends Drawable { private final Path mFullPath = new Path(); private final Path mForegroundPath = new Path(); private final Path mXPath = new Path(); + // Cut out when STATE_EMPTY + private final Path mCutPath = new Path(); + // Draws the slash when in airplane mode + private final SlashArtist mSlash = new SlashArtist(); private final Handler mHandler; private float mOldDarkIntensity = -1; private float mNumLevels = 1; @@ -126,6 +144,12 @@ public class SignalDrawable extends Drawable { mLightModeFillColor = Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill); mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size); + + // mCutPath parameters + mEmptyStrokeWidth = context.getResources() + .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth); + mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN; + mHandler = new Handler(); setDarkIntensity(0); @@ -224,9 +248,10 @@ public class SignalDrawable extends Drawable { } mFullPath.reset(); mFullPath.setFillType(FillType.WINDING); + final float width = getBounds().width(); final float height = getBounds().height(); - final float padding = (int) (PAD * width); // Stay on pixel boundary + final float padding = Math.round(PAD * width); final float cornerRadius = RADIUS_RATIO * height; // Offset from circle where the hypotenuse meets the circle final float diagOffset = DIAG_OFFSET_MULTIPLIER * cornerRadius; @@ -292,10 +317,37 @@ public class SignalDrawable extends Drawable { mFullPath.rLineTo(0, cut); } - mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); - mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); - - if (mState != STATE_CARRIER_CHANGE) { + if (mState == STATE_EMPTY) { + // Where the corners would be if this were a real triangle + mVirtualTop.set( + width - padding, + (padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius)); + mVirtualLeft.set( + (padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius), + height - padding); + + // Cut out a smaller triangle from the center of mFullPath + mCutPath.reset(); + mCutPath.setFillType(FillType.WINDING); + mCutPath.moveTo(width - padding - mEmptyStrokeWidth, + height - padding - mEmptyStrokeWidth); + mCutPath.lineTo(width - padding - mEmptyStrokeWidth, + mVirtualTop.y + mEmptyDiagInset); + mCutPath.lineTo(mVirtualLeft.x + mEmptyDiagInset, + height - padding - mEmptyStrokeWidth); + mCutPath.lineTo(width - padding - mEmptyStrokeWidth, + height - padding - mEmptyStrokeWidth); + + // In empty state, draw the full path as the foreground paint + mForegroundPath.set(mFullPath); + mFullPath.reset(); + mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE); + } else if (mState == STATE_AIRPLANE) { + // Airplane mode is slashed, full-signal + mForegroundPath.set(mFullPath); + mFullPath.reset(); + mSlash.draw((int) height, (int) width, canvas, mForegroundPaint); + } else if (mState != STATE_CARRIER_CHANGE) { mForegroundPath.reset(); int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding)); mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding, @@ -405,4 +457,65 @@ public class SignalDrawable extends Drawable { public static int getEmptyState(int numLevels) { return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); } + + public static int getAirplaneModeState(int numLevels) { + return (STATE_AIRPLANE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); + } + + private final class SlashArtist { + // These values are derived in un-rotated (vertical) orientation + private static final float SLASH_WIDTH = 1.8384776f; + private static final float SLASH_HEIGHT = 22f; + private static final float CENTER_X = 10.65f; + private static final float CENTER_Y = 15.869239f; + private static final float SCALE = 24f; + + // Bottom is derived during animation + private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE; + private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE; + private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE; + private static final float BOTTOM = (CENTER_Y + (SLASH_HEIGHT / 2)) / SCALE; + // Draw the slash washington-monument style; rotate to no-u-turn style + private static final float ROTATION = -45f; + + private final Path mPath = new Path(); + private final RectF mSlashRect = new RectF(); + + void draw(int height, int width, @NonNull Canvas canvas, Paint paint) { + Matrix m = new Matrix(); + updateRect( + scale(LEFT, width), + scale(TOP, height), + scale(RIGHT, width), + scale(BOTTOM, height)); + + mPath.reset(); + // Draw the slash vertically + mPath.addRect(mSlashRect, Direction.CW); + m.setRotate(ROTATION, width / 2, height / 2); + mPath.transform(m); + canvas.drawPath(mPath, paint); + + // Rotate back to vertical, and draw the cut-out rect next to this one + m.setRotate(-ROTATION, width / 2, height / 2); + mPath.transform(m); + m.setTranslate(mSlashRect.width(), 0); + mPath.transform(m); + mPath.addRect(mSlashRect, Direction.CW); + m.setRotate(ROTATION, width / 2, height / 2); + mPath.transform(m); + canvas.clipOutPath(mPath); + } + + void updateRect(float left, float top, float right, float bottom) { + mSlashRect.left = left; + mSlashRect.top = top; + mSlashRect.right = right; + mSlashRect.bottom = bottom; + } + + private float scale(float frac, int width) { + return frac * width; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d8db3222734d..4d6fd9c136b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3465,7 +3465,9 @@ public class StatusBar extends SystemUI implements DemoMode, pw.println(Settings.Global.zenModeToString(mZenMode)); pw.print(" mUseHeadsUp="); pw.println(mUseHeadsUp); - dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); + if (mStatusBarView != null) { + dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); + } pw.print(" mMediaSessionManager="); pw.println(mMediaSessionManager); @@ -3531,7 +3533,9 @@ public class StatusBar extends SystemUI implements DemoMode, pw.println(" mGroupManager: null"); } - mLightBarController.dump(fd, pw, args); + if (mLightBarController != null) { + mLightBarController.dump(fd, pw, args); + } if (KeyguardUpdateMonitor.getInstance(mContext) != null) { KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java index 3f5f5a0ed5ae..874f0d9d5b5f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java @@ -31,8 +31,10 @@ import android.os.Message; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.support.annotation.VisibleForTesting; import com.android.systemui.R; +import com.android.systemui.util.Utils; import java.util.ArrayList; import java.util.List; @@ -141,7 +143,8 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio /** * Returns true if there currently exist active high power location requests. */ - private boolean areActiveHighPowerLocationRequests() { + @VisibleForTesting + protected boolean areActiveHighPowerLocationRequests() { List<AppOpsManager.PackageOps> packages = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray); // AppOpsManager can return null when there is no requested data. @@ -205,16 +208,14 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio } private void locationActiveChanged() { - for (LocationChangeCallback cb : mSettingsChangeCallbacks) { - cb.onLocationActiveChanged(mAreActiveLocationRequests); - } + Utils.safeForeach(mSettingsChangeCallbacks, + cb -> cb.onLocationActiveChanged(mAreActiveLocationRequests)); } private void locationSettingsChanged() { boolean isEnabled = isLocationEnabled(); - for (LocationChangeCallback cb : mSettingsChangeCallbacks) { - cb.onLocationSettingsChanged(isEnabled); - } + Utils.safeForeach(mSettingsChangeCallbacks, + cb -> cb.onLocationSettingsChanged(isEnabled)); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 67b5596e34c9..bd7fee0f7f52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -235,6 +235,9 @@ public class MobileSignalController extends SignalController< } private int getNumLevels() { + if (mConfig.inflateSignalStrengths) { + return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1; + } return SignalStrength.NUM_SIGNAL_STRENGTH_BINS; } @@ -243,7 +246,11 @@ public class MobileSignalController extends SignalController< if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) { return SignalDrawable.getCarrierChangeState(getNumLevels()); } else if (mCurrentState.connected) { - return SignalDrawable.getState(mCurrentState.level, getNumLevels(), + int level = mCurrentState.level; + if (mConfig.inflateSignalStrengths) { + level++; + } + return SignalDrawable.getState(level, getNumLevels(), mCurrentState.inetCondition == 0); } else if (mCurrentState.enabled) { return SignalDrawable.getEmptyState(getNumLevels()); @@ -254,6 +261,10 @@ public class MobileSignalController extends SignalController< @Override public int getQsCurrentIconId() { + if (mCurrentState.airplaneMode) { + return SignalDrawable.getAirplaneModeState(getNumLevels()); + } + return getCurrentIconId(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 39f7d1295d1b..c217bda935c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -958,6 +958,7 @@ public class NetworkControllerImpl extends BroadcastReceiver boolean show4gForLte = false; boolean hideLtePlus = false; boolean hspaDataDistinguishable; + boolean inflateSignalStrengths = false; static Config readConfig(Context context) { Config config = new Config(); @@ -970,6 +971,7 @@ public class NetworkControllerImpl extends BroadcastReceiver config.hspaDataDistinguishable = res.getBoolean(R.bool.config_hspa_data_distinguishable); config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus); + config.inflateSignalStrengths = res.getBoolean(R.bool.config_inflateSignalStrength); return config; } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 2742fdd0dd84..2b2ad693608e 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -18,7 +18,6 @@ package com.android.systemui.volume; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.ObjectAnimator; @@ -32,10 +31,12 @@ import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.AudioSystem; @@ -48,9 +49,11 @@ import android.provider.Settings.Global; import android.transition.AutoTransition; import android.transition.Transition; import android.transition.TransitionManager; +import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; +import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -71,7 +74,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.android.settingslib.Utils; import com.android.systemui.Dependency; -import com.android.systemui.HardwareUiLayout; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -96,8 +98,7 @@ import java.util.List; * * Methods ending in "H" must be called on the (ui) handler. */ -public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, - ColorExtractor.OnColorsChangedListener { +public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { private static final String TAG = Util.logTag(VolumeDialogImpl.class); public static final String SHOW_FULL_ZEN = "sysui_show_full_zen"; @@ -107,8 +108,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, private final Context mContext; private final H mHandler = new H(); - private final GradientDrawable mGradientDrawable; - private final ColorExtractor mColorExtractor; private final VolumeDialogController mController; private Window mWindow; @@ -163,9 +162,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext)); mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive); - mGradientDrawable = new GradientDrawable(mContext); - mGradientDrawable.setAlpha((int) (ScrimController.GRADIENT_SCRIM_ALPHA * 255)); - mColorExtractor = Dependency.get(SysuiColorExtractor.class); } public void init(int windowType, Callback callback) { @@ -187,7 +183,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, @Override public void destroy() { mController.removeCallback(mControllerCallbackH); - mColorExtractor.removeOnColorsChangedListener(this); } private void initDialog() { @@ -198,52 +193,64 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, mShowing = false; mWindow = mDialog.getWindow(); mWindow.requestFeature(Window.FEATURE_NO_TITLE); - mWindow.setBackgroundDrawable(mGradientDrawable); + mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); - Point displaySize = new Point(); - mContext.getDisplay().getRealSize(displaySize); + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); mDialog.setCanceledOnTouchOutside(true); final Resources res = mContext.getResources(); + final WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.type = mWindowType; + lp.format = PixelFormat.TRANSLUCENT; + lp.setTitle(VolumeDialogImpl.class.getSimpleName()); + lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top); + lp.gravity = Gravity.TOP; + lp.windowAnimations = -1; + mWindow.setAttributes(lp); mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); - mDialog.setContentView(R.layout.volume_dialog_wrapped); - mDialogView = mDialog.findViewById(R.id.volume_dialog); - mDialogView.setOnHoverListener((v, event) -> { - int action = event.getActionMasked(); - mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) - || (action == MotionEvent.ACTION_HOVER_MOVE); - rescheduleTimeoutH(); - return true; + mDialog.setContentView(R.layout.volume_dialog); + mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog); + mDialogView.setOnHoverListener(new View.OnHoverListener() { + @Override + public boolean onHover(View v, MotionEvent event) { + int action = event.getActionMasked(); + mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) + || (action == MotionEvent.ACTION_HOVER_MOVE); + rescheduleTimeoutH(); + return true; + } }); - mColorExtractor.addOnColorsChangedListener(this); - mGradientDrawable.setScreenSize(displaySize.x, displaySize.y); - mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content); mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows); mExpanded = false; - mExpandButton = mDialogView.findViewById(R.id.volume_expand_button); + mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button); mExpandButton.setOnClickListener(mClickExpand); mExpandButton.setVisibility( AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE); + updateWindowWidthH(); updateExpandButtonH(); - mMotion = new VolumeDialogMotion(mDialog, (View) mDialogView.getParent(), - mDialogContentView, mExpandButton, mGradientDrawable, animating -> { - if (animating) return; - if (mPendingStateChanged) { - mHandler.sendEmptyMessage(H.STATE_CHANGED); - mPendingStateChanged = false; - } - if (mPendingRecheckAll) { - mHandler.sendEmptyMessage(H.RECHECK_ALL); - mPendingRecheckAll = false; + mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton, + new VolumeDialogMotion.Callback() { + @Override + public void onAnimatingChanged(boolean animating) { + if (animating) return; + if (mPendingStateChanged) { + mHandler.sendEmptyMessage(H.STATE_CHANGED); + mPendingStateChanged = false; + } + if (mPendingRecheckAll) { + mHandler.sendEmptyMessage(H.RECHECK_ALL); + mPendingRecheckAll = false; + } } }); @@ -268,20 +275,11 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, addExistingRows(); } mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration); - mZenFooter = mDialog.findViewById(R.id.volume_zen_footer); + mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer); mZenFooter.init(mZenModeController); - mZenPanel = mDialog.findViewById(R.id.tuner_zen_mode_panel); + mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel); mZenPanel.init(mZenModeController); mZenPanel.setCallback(mZenPanelCallback); - - final WindowManager.LayoutParams lp = mWindow.getAttributes(); - lp.width = MATCH_PARENT; - lp.height = MATCH_PARENT; - lp.type = mWindowType; - lp.format = PixelFormat.TRANSLUCENT; - lp.setTitle(VolumeDialogImpl.class.getSimpleName()); - lp.windowAnimations = -1; - mWindow.setAttributes(lp); } @Override @@ -295,6 +293,20 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, return ColorStateList.valueOf(mContext.getColor(colorResId)); } + private void updateWindowWidthH() { + final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams(); + final DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); + if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels); + int w = dm.widthPixels; + final int max = mContext.getResources() + .getDimensionPixelSize(R.dimen.volume_dialog_panel_width); + if (w > max) { + w = max; + } + lp.width = w; + mDialogView.setLayoutParams(lp); + } + public void setStreamImportant(int stream, boolean important) { mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget(); } @@ -478,10 +490,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, rescheduleTimeoutH(); if (mShowing) return; mShowing = true; - ColorExtractor.GradientColors colors = mColorExtractor.getColors( - mKeyguard.isKeyguardLocked() ? WallpaperManager.FLAG_LOCK - : WallpaperManager.FLAG_SYSTEM); - mGradientDrawable.setColors(colors, false); mMotion.startShow(); Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); mController.notifyVisible(true); @@ -539,8 +547,10 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, } private void updateDialogBottomMarginH() { + final long diff = System.currentTimeMillis() - mCollapseTime; + final boolean collapsing = mCollapseTime != 0 && diff < getConservativeCollapseDuration(); final ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams(); - final int bottomMargin = + final int bottomMargin = collapsing ? mDialogContentView.getHeight() : mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom); if (bottomMargin != mlp.bottomMargin) { if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin); @@ -570,7 +580,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, TransitionManager.endTransitions(mDialogView); final VolumeRow activeRow = getActiveRow(); if (!dismissing) { - mWindow.setLayout(mWindow.getAttributes().width, MATCH_PARENT); + mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT); TransitionManager.beginDelayedTransition(mDialogView, getTransition()); } updateRowsH(activeRow); @@ -632,7 +642,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, final boolean isActive = row == activeRow; final boolean shouldBeVisible = shouldBeVisibleH(row, isActive); Util.setVisOrGone(row.view, shouldBeVisible); - Util.setVisOrGone(row.header, shouldBeVisible && mExpanded); + Util.setVisOrGone(row.header, shouldBeVisible); if (row.view.isShown()) { updateVolumeRowSliderTintH(row, isActive); } @@ -689,18 +699,12 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded) && !mZenPanel.isEditing(); - - if (wasVisible != visible) { - mZenFooter.update(); - if (visible) { - HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter); - } else { - mHandler.postDelayed(() -> - HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter), - mExpandButtonAnimationDuration); - } - Util.setVisOrGone(mZenFooter, visible); + TransitionManager.beginDelayedTransition(mDialogView, getTransition()); + if (wasVisible != visible && !visible) { + prepareForCollapse(); } + Util.setVisOrGone(mZenFooter, visible); + mZenFooter.update(); final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE; final boolean fullVisible = mShowFullZen && !visible; @@ -960,7 +964,8 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, @Override public void onTransitionEnd(Transition transition) { - mWindow.setLayout(MATCH_PARENT, MATCH_PARENT); + mWindow.setLayout( + mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override @@ -969,7 +974,8 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, @Override public void onTransitionPause(Transition transition) { - mWindow.setLayout(MATCH_PARENT, MATCH_PARENT); + mWindow.setLayout( + mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override @@ -1021,6 +1027,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, initDialog(); mDensity = density; } + updateWindowWidthH(); mConfigurableTexts.update(); mZenFooter.onConfigurationChanged(); } @@ -1076,26 +1083,10 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, if (mExpandButtonAnimationRunning) return; final boolean newExpand = !mExpanded; Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand); - if (!newExpand) { - HardwareUiLayout.get(mDialogContentView).setCollapse(); - } updateExpandedH(newExpand, false /* dismissing */); } }; - @Override - public void onColorsChanged(ColorExtractor extractor, int which) { - if (mKeyguard.isKeyguardLocked()) { - if ((WallpaperManager.FLAG_LOCK & which) != 0) { - mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK)); - } - } else { - if ((WallpaperManager.FLAG_SYSTEM & which) != 0) { - mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM)); - } - } - } - private final class H extends Handler { private static final int SHOW = 1; private static final int DISMISS = 2; @@ -1167,8 +1158,8 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable, event.setPackageName(mContext.getPackageName()); ViewGroup.LayoutParams params = getWindow().getAttributes(); - boolean isFullScreen = (params.width == MATCH_PARENT) && - (params.height == MATCH_PARENT); + boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) && + (params.height == ViewGroup.LayoutParams.MATCH_PARENT); event.setFullScreen(isFullScreen); if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java index 2df222764dcc..01d31e2a9852 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.systemui.volume; import android.animation.Animator; @@ -41,10 +42,8 @@ public class VolumeDialogMotion { private final View mDialogView; private final ViewGroup mContents; // volume rows + zen footer private final View mChevron; - private final Drawable mBackground; private final Handler mHandler = new Handler(); private final Callback mCallback; - private final int mBackgroundTargetAlpha; private boolean mAnimating; // show or dismiss animation is running private boolean mShowing; // show animation is running @@ -53,14 +52,12 @@ public class VolumeDialogMotion { private ValueAnimator mContentsPositionAnimator; public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron, - Drawable background, Callback callback) { + Callback callback) { mDialog = dialog; mDialogView = dialogView; mContents = contents; mChevron = chevron; mCallback = callback; - mBackground = background; - mBackgroundTargetAlpha = mBackground.getAlpha(); mDialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { @@ -71,9 +68,8 @@ public class VolumeDialogMotion { @Override public void onShow(DialogInterface dialog) { if (D.BUG) Log.d(TAG, "mDialog.onShow"); - final int w = mDialogView.getWidth() / 4; - mDialogView.setTranslationX(w); - mBackground.setAlpha(0); + final int h = mDialogView.getHeight(); + mDialogView.setTranslationY(-h); startShowAnimation(); } }); @@ -122,7 +118,7 @@ public class VolumeDialogMotion { } private int chevronDistance() { - return 0; + return mChevron.getHeight() / 6; } private int chevronPosY() { @@ -133,29 +129,26 @@ public class VolumeDialogMotion { private void startShowAnimation() { if (D.BUG) Log.d(TAG, "startShowAnimation"); mDialogView.animate() - .translationX(0) .translationY(0) - .alpha(1) .setDuration(scaledDuration(300)) .setInterpolator(new LogDecelerateInterpolator()) .setListener(null) .setUpdateListener(animation -> { - mBackground.setAlpha( - (int) (animation.getAnimatedFraction() * mBackgroundTargetAlpha)); if (mChevronPositionAnimator != null) { final float v = (Float) mChevronPositionAnimator.getAnimatedValue(); if (mChevronPositionAnimator == null) return; // reposition chevron final int posY = chevronPosY(); + mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY()); } }) .withEndAction(new Runnable() { @Override public void run() { - mBackground.setAlpha(mBackgroundTargetAlpha); if (mChevronPositionAnimator == null) return; // reposition chevron final int posY = chevronPosY(); + mChevron.setTranslationY(posY + -mDialogView.getTranslationY()); } }) .start(); @@ -171,13 +164,19 @@ public class VolumeDialogMotion { if (D.BUG) Log.d(TAG, "show.onAnimationEnd"); setShowing(false); } - @Override public void onAnimationCancel(Animator animation) { if (D.BUG) Log.d(TAG, "show.onAnimationCancel"); mCancelled = true; } }); + mContentsPositionAnimator.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float v = (Float) animation.getAnimatedValue(); + mContents.setTranslationY(v + -mDialogView.getTranslationY()); + } + }); mContentsPositionAnimator.setInterpolator(new LogDecelerateInterpolator()); mContentsPositionAnimator.start(); @@ -219,30 +218,34 @@ public class VolumeDialogMotion { setShowing(false); } mDialogView.animate() - .translationX(mDialogView.getWidth() / 4) - .alpha(0) + .translationY(-mDialogView.getHeight()) .setDuration(scaledDuration(250)) .setInterpolator(new LogAccelerateInterpolator()) - .setUpdateListener(animation -> { - final float v = 1 - mChevronPositionAnimator.getAnimatedFraction(); - mBackground.setAlpha((int) (v * mBackgroundTargetAlpha)); + .setUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mContents.setTranslationY(-mDialogView.getTranslationY()); + final int posY = chevronPosY(); + mChevron.setTranslationY(posY + -mDialogView.getTranslationY()); + } }) .setListener(new AnimatorListenerAdapter() { private boolean mCancelled; - @Override public void onAnimationEnd(Animator animation) { if (mCancelled) return; if (D.BUG) Log.d(TAG, "dismiss.onAnimationEnd"); - mHandler.postDelayed(() -> { - if (D.BUG) Log.d(TAG, "mDialog.dismiss()"); - mDialog.dismiss(); - onComplete.run(); - setDismissing(false); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (D.BUG) Log.d(TAG, "mDialog.dismiss()"); + mDialog.dismiss(); + onComplete.run(); + setDismissing(false); + } }, PRE_DISMISS_DELAY); } - @Override public void onAnimationCancel(Animator animation) { if (D.BUG) Log.d(TAG, "dismiss.onAnimationCancel"); diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 612a54a8d70d..b12fd1c9ba89 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -37,6 +37,7 @@ <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java index 68f9cb05ecaf..8e7ffdfd4b47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java @@ -16,8 +16,10 @@ package com.android.systemui.statusbar; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -33,12 +35,14 @@ import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.graphics.Color; import android.graphics.drawable.Icon; import android.os.UserHandle; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.util.NotificationColorUtil; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -100,4 +104,17 @@ public class StatusBarIconViewTest extends SysuiTestCase { assertFalse(mIconView.set(mStatusBarIcon)); } + + @Test + public void testGetContrastedStaticDrawableColor() { + mIconView.setStaticDrawableColor(Color.DKGRAY); + int color = mIconView.getContrastedStaticDrawableColor(Color.WHITE); + assertEquals("Color should not change when we have enough contrast", + Color.DKGRAY, color); + + mIconView.setStaticDrawableColor(Color.WHITE); + color = mIconView.getContrastedStaticDrawableColor(Color.WHITE); + assertTrue("Similar colors should be shifted to satisfy contrast", + NotificationColorUtil.satisfiesTextContrast(Color.WHITE, color)); + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 0e3ea7a07e7d..17ca92458bcf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -38,6 +38,8 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; import android.app.Notification; +import android.app.trust.TrustManager; +import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; import android.os.Handler; import android.os.HandlerThread; @@ -55,6 +57,7 @@ import android.testing.TestableLooper; import android.testing.TestableLooper.MessageHandler; import android.testing.TestableLooper.RunWithLooper; import android.util.DisplayMetrics; +import android.view.ViewGroup.LayoutParams; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -75,6 +78,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; import java.util.ArrayList; @SmallTest @@ -99,6 +104,8 @@ public class StatusBarTest extends SysuiTestCase { @Before public void setup() throws Exception { + mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); + mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class); mUnlockMethodCache = mock(UnlockMethodCache.class); mKeyguardIndicationController = mock(KeyguardIndicationController.class); @@ -108,6 +115,7 @@ public class StatusBarTest extends SysuiTestCase { mNotificationData = mock(NotificationData.class); mSystemServicesProxy = mock(SystemServicesProxy.class); mNotificationPanelView = mock(NotificationPanelView.class); + when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); mNotificationList = mock(ArrayList.class); IPowerManager powerManagerService = mock(IPowerManager.class); HandlerThread handlerThread = new HandlerThread("TestThread"); @@ -122,6 +130,7 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardIndicationController, mStackScroller, mHeadsUpManager, mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView, mBarService); + mStatusBar.mContext = mContext; doAnswer(invocation -> { OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0]; onDismissAction.onDismiss(); @@ -385,6 +394,11 @@ public class StatusBarTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); } + @Test + public void testDump_DoesNotCrash() { + mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null); + } + static class TestableStatusBar extends StatusBar { public TestableStatusBar(StatusBarKeyguardViewManager man, UnlockMethodCache unlock, KeyguardIndicationController key, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java new file mode 100644 index 000000000000..a10bebfd4f2d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java @@ -0,0 +1,82 @@ +/* + * 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.systemui.statusbar.policy; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.location.LocationManager; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class LocationControllerImplTest extends SysuiTestCase { + + private LocationControllerImpl mLocationController; + + @Before + public void setup() { + mLocationController = spy(new LocationControllerImpl(mContext, + TestableLooper.get(this).getLooper())); + } + + @Test + public void testRemoveSelfActive_DoesNotCrash() { + LocationController.LocationChangeCallback callback = new LocationChangeCallback() { + @Override + public void onLocationActiveChanged(boolean active) { + mLocationController.removeCallback(this); + } + }; + mLocationController.addCallback(callback); + mLocationController.addCallback(mock(LocationChangeCallback.class)); + + when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(false); + mLocationController.onReceive(mContext, new Intent( + LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION)); + when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(true); + mLocationController.onReceive(mContext, new Intent( + LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION)); + + TestableLooper.get(this).processAllMessages(); + } + + @Test + public void testRemoveSelfSettings_DoesNotCrash() { + LocationController.LocationChangeCallback callback = new LocationChangeCallback() { + @Override + public void onLocationSettingsChanged(boolean isEnabled) { + mLocationController.removeCallback(this); + } + }; + mLocationController.addCallback(callback); + mLocationController.addCallback(mock(LocationChangeCallback.class)); + + TestableLooper.get(this).processAllMessages(); + } +}
\ No newline at end of file diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index f696f94cae1f..b3a4007ff399 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4124,6 +4124,16 @@ message MetricsEvent { // OS: O DR ACTION_PSD_LOADER = 1019; + // ACTION: Background check action on an app + // CATEGORY: SETTINGS + // OS: O DR + ACTION_APP_BACKGROUND_CHECK = 1020; + + // ACTION: Location check action on an app + // CATEGORY: SETTINGS + // OS: O DR + ACTION_APP_LOCATION_CHECK = 1021; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index e85f96be3160..71f699c8da54 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -270,6 +270,12 @@ public final class AutofillManagerService extends SystemService { } @Override + public void onSwitchUser(int userHandle) { + if (sDebug) Slog.d(TAG, "Hiding UI when user switched"); + mUi.hideAll(null); + } + + @Override public void onCleanupUser(int userId) { synchronized (mLock) { removeCachedServiceLocked(userId); @@ -458,6 +464,7 @@ public final class AutofillManagerService extends SystemService { private void updateCachedServiceLocked(int userId, boolean disabled) { AutofillManagerServiceImpl service = getServiceForUserLocked(userId); if (service != null) { + service.destroySessionsLocked(); service.updateLocked(disabled); if (!service.isEnabled()) { removeCachedServiceLocked(userId); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 1a02e8d8eb97..751c0547afd6 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -360,8 +360,7 @@ final class AutofillManagerServiceImpl { } void disableOwnedAutofillServicesLocked(int uid) { - if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid - != UserHandle.getAppId(uid)) { + if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid != uid) { return; } final long identity = Binder.clearCallingIdentity(); 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 d1fbbf9ceda1..c9e2a928dee0 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -191,6 +191,7 @@ final class SaveUi { | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); + window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS); window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); window.setGravity(Gravity.BOTTOM | Gravity.CENTER); window.setCloseOnTouchOutside(true); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 72754616133a..eda283e82d79 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -324,58 +324,13 @@ public class LocationManagerService extends ILocationManager.Stub { ActivityManager.OnUidImportanceListener uidImportanceListener = new ActivityManager.OnUidImportanceListener() { @Override - public void onUidImportance(int uid, int importance) { - boolean foreground = isImportanceForeground(importance); - HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size()); - synchronized (mLock) { - for (Entry<String, ArrayList<UpdateRecord>> entry - : mRecordsByProvider.entrySet()) { - String provider = entry.getKey(); - for (UpdateRecord record : entry.getValue()) { - if (record.mReceiver.mIdentity.mUid == uid - && record.mIsForegroundUid != foreground) { - if (D) Log.d(TAG, "request from uid " + uid + " is now " - + (foreground ? "foreground" : "background)")); - record.mIsForegroundUid = foreground; - - if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) { - affectedProviders.add(provider); - } - } - } - } - for (String provider : affectedProviders) { - applyRequirementsLocked(provider); - } - - for (Entry<IGnssMeasurementsListener, Identity> entry - : mGnssMeasurementsListeners.entrySet()) { - if (entry.getValue().mUid == uid) { - if (D) Log.d(TAG, "gnss measurements listener from uid " + uid - + " is now " + (foreground ? "foreground" : "background)")); - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssMeasurementsProvider.addListener(entry.getKey()); - } else { - mGnssMeasurementsProvider.removeListener(entry.getKey()); - } - } - } - - for (Entry<IGnssNavigationMessageListener, Identity> entry - : mGnssNavigationMessageListeners.entrySet()) { - if (entry.getValue().mUid == uid) { - if (D) Log.d(TAG, "gnss navigation message listener from uid " - + uid + " is now " - + (foreground ? "foreground" : "background)")); - if (foreground || isThrottlingExemptLocked(entry.getValue())) { - mGnssNavigationMessageProvider.addListener(entry.getKey()); - } else { - mGnssNavigationMessageProvider.removeListener(entry.getKey()); - } - } + public void onUidImportance(final int uid, final int importance) { + mLocationHandler.post(new Runnable() { + @Override + public void run() { + onUidImportanceChanged(uid, importance); } - } - + }); } }; mActivityManager.addOnUidImportanceListener(uidImportanceListener, @@ -455,6 +410,59 @@ public class LocationManagerService extends ILocationManager.Stub { }, UserHandle.ALL, intentFilter, null, mLocationHandler); } + private void onUidImportanceChanged(int uid, int importance) { + boolean foreground = isImportanceForeground(importance); + HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size()); + synchronized (mLock) { + for (Entry<String, ArrayList<UpdateRecord>> entry + : mRecordsByProvider.entrySet()) { + String provider = entry.getKey(); + for (UpdateRecord record : entry.getValue()) { + if (record.mReceiver.mIdentity.mUid == uid + && record.mIsForegroundUid != foreground) { + if (D) Log.d(TAG, "request from uid " + uid + " is now " + + (foreground ? "foreground" : "background)")); + record.mIsForegroundUid = foreground; + + if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) { + affectedProviders.add(provider); + } + } + } + } + for (String provider : affectedProviders) { + applyRequirementsLocked(provider); + } + + for (Entry<IGnssMeasurementsListener, Identity> entry + : mGnssMeasurementsListeners.entrySet()) { + if (entry.getValue().mUid == uid) { + if (D) Log.d(TAG, "gnss measurements listener from uid " + uid + + " is now " + (foreground ? "foreground" : "background)")); + if (foreground || isThrottlingExemptLocked(entry.getValue())) { + mGnssMeasurementsProvider.addListener(entry.getKey()); + } else { + mGnssMeasurementsProvider.removeListener(entry.getKey()); + } + } + } + + for (Entry<IGnssNavigationMessageListener, Identity> entry + : mGnssNavigationMessageListeners.entrySet()) { + if (entry.getValue().mUid == uid) { + if (D) Log.d(TAG, "gnss navigation message listener from uid " + + uid + " is now " + + (foreground ? "foreground" : "background)")); + if (foreground || isThrottlingExemptLocked(entry.getValue())) { + mGnssNavigationMessageProvider.addListener(entry.getKey()); + } else { + mGnssNavigationMessageProvider.removeListener(entry.getKey()); + } + } + } + } + } + private static boolean isImportanceForeground(int importance) { return importance <= FOREGROUND_IMPORTANCE_CUTOFF; } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 86c8909942ac..8ea334dbfb17 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1058,6 +1058,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override + public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException { + try { + mNetdService.setIPv6AddrGenMode(iface, mode); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + @Override public void disableIpv6(String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 3948ee1c3d1a..a54fe727f57e 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -162,7 +162,8 @@ public class AccountManagerService @Override public void onStopUser(int userHandle) { - mService.onStopUser(userHandle); + Slog.i(TAG, "onStopUser " + userHandle); + mService.purgeUserData(userHandle); } } @@ -314,6 +315,21 @@ public class AccountManagerService injector.addLocalService(new AccountManagerInternalImpl()); + 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)) { + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId < 1) return; + Slog.i(TAG, "User " + userId + " removed"); + purgeUserData(userId); + } + } + }, UserHandle.ALL, userFilter, null, null); + // Need to cancel account request notifications if the update/install can access the account new PackageMonitor() { @Override @@ -1360,9 +1376,7 @@ public class AccountManagerService } } - - private void onStopUser(int userId) { - Log.i(TAG, "onStopUser " + userId); + private void purgeUserData(int userId) { UserAccounts accounts; synchronized (mUsers) { accounts = mUsers.get(userId); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e5ab784df882..c6307a793e34 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -706,6 +706,8 @@ public class AudioService extends IAudioService.Stub mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor); + mRecordMonitor = new RecordingActivityMonitor(mContext); + readAndSetLowRamDevice(); // Call setRingerModeInt() to apply correct mute @@ -6309,6 +6311,8 @@ public class AudioService extends IAudioService.Stub dumpAudioPolicies(pw); mPlaybackMonitor.dump(pw); + + mRecordMonitor.dump(pw); } private static String safeMediaVolumeStateToString(Integer state) { @@ -6730,10 +6734,13 @@ public class AudioService extends IAudioService.Stub //====================== // Audio policy callbacks from AudioSystem for recording configuration updates //====================== - private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor(); + private final RecordingActivityMonitor mRecordMonitor; public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) { - mRecordMonitor.registerRecordingCallback(rcdb); + final boolean isPrivileged = + (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission( + android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged); } public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) { @@ -6741,7 +6748,10 @@ public class AudioService extends IAudioService.Stub } public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { - return mRecordMonitor.getActiveRecordingConfigurations(); + final boolean isPrivileged = + (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission( + android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged); } public void disableRingtoneSync(final int userId) { diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java index 57d55de8d002..34309b62d2f7 100644 --- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java +++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java @@ -16,8 +16,11 @@ package com.android.server.audio; +import android.content.Context; +import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioManager; +import android.media.AudioPlaybackConfiguration; import android.media.AudioRecordingConfiguration; import android.media.AudioSystem; import android.media.IRecordingConfigDispatcher; @@ -26,7 +29,10 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import java.io.PrintWriter; +import java.text.DateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -39,31 +45,47 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin public final static String TAG = "AudioService.RecordingActivityMonitor"; private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>(); + // a public client is one that needs an anonymized version of the playback configurations, we + // keep track of whether there is at least one to know when we need to create the list of + // playback configurations that do not contain uid/package name information. + private boolean mHasPublicClients = false; private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs = new HashMap<Integer, AudioRecordingConfiguration>(); - RecordingActivityMonitor() { + private final PackageManager mPackMan; + + RecordingActivityMonitor(Context ctxt) { RecMonitorClient.sMonitor = this; + mPackMan = ctxt.getPackageManager(); } /** * Implementation of android.media.AudioSystem.AudioRecordingCallback */ - public void onRecordingConfigurationChanged(int event, int session, int source, - int[] recordingInfo) { + public void onRecordingConfigurationChanged(int event, int uid, int session, int source, + int[] recordingInfo, String packName) { if (MediaRecorder.isSystemOnlyAudioSource(source)) { return; } - final List<AudioRecordingConfiguration> configs = - updateSnapshot(event, session, source, recordingInfo); - if (configs != null){ - synchronized(mClients) { + final List<AudioRecordingConfiguration> configsSystem = + updateSnapshot(event, uid, session, source, recordingInfo); + if (configsSystem != null){ + synchronized (mClients) { + // list of recording configurations for "public consumption". It is only computed if + // there are non-system recording activity listeners. + final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients ? + anonymizeForPublicConsumption(configsSystem) : + new ArrayList<AudioRecordingConfiguration>(); final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); while (clientIterator.hasNext()) { + final RecMonitorClient rmc = clientIterator.next(); try { - clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange( - configs); + if (rmc.mIsPrivileged) { + rmc.mDispatcherCb.dispatchRecordingConfigChange(configsSystem); + } else { + rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic); + } } catch (RemoteException e) { Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e); } @@ -72,17 +94,42 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin } } + protected void dump(PrintWriter pw) { + // players + pw.println("\nRecordActivityMonitor dump time: " + + DateFormat.getTimeInstance().format(new Date())); + synchronized(mRecordConfigs) { + for (AudioRecordingConfiguration conf : mRecordConfigs.values()) { + conf.dump(pw); + } + } + } + + private ArrayList<AudioRecordingConfiguration> anonymizeForPublicConsumption( + List<AudioRecordingConfiguration> sysConfigs) { + ArrayList<AudioRecordingConfiguration> publicConfigs = + new ArrayList<AudioRecordingConfiguration>(); + // only add active anonymized configurations, + for (AudioRecordingConfiguration config : sysConfigs) { + publicConfigs.add(AudioRecordingConfiguration.anonymizedCopy(config)); + } + return publicConfigs; + } + void initMonitor() { AudioSystem.setRecordingCallback(this); } - void registerRecordingCallback(IRecordingConfigDispatcher rcdb) { + void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) { if (rcdb == null) { return; } - synchronized(mClients) { - final RecMonitorClient rmc = new RecMonitorClient(rcdb); + synchronized (mClients) { + final RecMonitorClient rmc = new RecMonitorClient(rcdb, isPrivileged); if (rmc.init()) { + if (!isPrivileged) { + mHasPublicClients = true; + } mClients.add(rmc); } } @@ -92,22 +139,34 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin if (rcdb == null) { return; } - synchronized(mClients) { + synchronized (mClients) { final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); + boolean hasPublicClients = false; while (clientIterator.hasNext()) { RecMonitorClient rmc = clientIterator.next(); if (rcdb.equals(rmc.mDispatcherCb)) { rmc.release(); clientIterator.remove(); - break; + } else { + if (!rmc.mIsPrivileged) { + hasPublicClients = true; + } } } + mHasPublicClients = hasPublicClients; } } - List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { + List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) { synchronized(mRecordConfigs) { - return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()); + if (isPrivileged) { + return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()); + } else { + final List<AudioRecordingConfiguration> configsPublic = + anonymizeForPublicConsumption( + new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values())); + return configsPublic; + } } } @@ -122,8 +181,8 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin * @return null if the list of active recording sessions has not been modified, a list * with the current active configurations otherwise. */ - private List<AudioRecordingConfiguration> updateSnapshot(int event, int session, int source, - int[] recordingInfo) { + private List<AudioRecordingConfiguration> updateSnapshot(int event, int uid, int session, + int source, int[] recordingInfo) { final boolean configChanged; final ArrayList<AudioRecordingConfiguration> configs; synchronized(mRecordConfigs) { @@ -147,10 +206,19 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin .build(); final int patchHandle = recordingInfo[6]; final Integer sessionKey = new Integer(session); + + final String[] packages = mPackMan.getPackagesForUid(uid); + final String packageName; + if (packages != null && packages.length > 0) { + packageName = packages[0]; + } else { + packageName = ""; + } + final AudioRecordingConfiguration updatedConfig = + new AudioRecordingConfiguration(uid, session, source, + clientFormat, deviceFormat, patchHandle, packageName); + if (mRecordConfigs.containsKey(sessionKey)) { - final AudioRecordingConfiguration updatedConfig = - new AudioRecordingConfiguration(session, source, - clientFormat, deviceFormat, patchHandle); if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) { configChanged = false; } else { @@ -160,9 +228,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin configChanged = true; } } else { - mRecordConfigs.put(sessionKey, - new AudioRecordingConfiguration(session, source, - clientFormat, deviceFormat, patchHandle)); + mRecordConfigs.put(sessionKey, updatedConfig); configChanged = true; } break; @@ -189,9 +255,11 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin static RecordingActivityMonitor sMonitor; final IRecordingConfigDispatcher mDispatcherCb; + final boolean mIsPrivileged; - RecMonitorClient(IRecordingConfigDispatcher rcdb) { + RecMonitorClient(IRecordingConfigDispatcher rcdb, boolean isPrivileged) { mDispatcherCb = rcdb; + mIsPrivileged = isPrivileged; } public void binderDied() { diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 4a45c074f4d1..da7572274497 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -466,6 +466,11 @@ public class GnssLocationProvider implements LocationProviderInterface { // Always on, notify HAL so it can get data it needs sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); } + + @Override + public void onLost(Network network) { + sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); + } }; /** @@ -802,11 +807,21 @@ public class GnssLocationProvider implements LocationProviderInterface { private void handleUpdateNetworkState(Network network) { // retrieve NetworkInfo for this UID NetworkInfo info = mConnMgr.getNetworkInfo(network); - if (info == null) { - return; + + boolean networkAvailable = false; + boolean isConnected = false; + int type = ConnectivityManager.TYPE_NONE; + boolean isRoaming = false; + String apnName = null; + + if (info != null) { + networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled(); + isConnected = info.isConnected(); + type = info.getType(); + isRoaming = info.isRoaming(); + apnName = info.getExtraInfo(); } - boolean isConnected = info.isConnected(); if (DEBUG) { String message = String.format( "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S", @@ -818,8 +833,6 @@ public class GnssLocationProvider implements LocationProviderInterface { } if (native_is_agps_ril_supported()) { - boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled(); - boolean networkAvailable = info.isAvailable() && dataEnabled; String defaultApn = getSelectedApn(); if (defaultApn == null) { defaultApn = "dummy-apn"; @@ -827,10 +840,10 @@ public class GnssLocationProvider implements LocationProviderInterface { native_update_network_state( isConnected, - info.getType(), - info.isRoaming(), + type, + isRoaming, networkAvailable, - info.getExtraInfo(), + apnName, defaultApn); } else if (DEBUG) { Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); @@ -838,7 +851,6 @@ public class GnssLocationProvider implements LocationProviderInterface { if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { if (isConnected) { - String apnName = info.getExtraInfo(); if (apnName == null) { // assign a dummy value in the case of C2K as otherwise we will have a runtime // exception in the following call to native_agps_data_conn_open diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2ac7e5043518..c1c14e8a2cef 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1057,14 +1057,12 @@ public class PackageManagerService extends IPackageManager.Stub scheduleWriteSettingsLocked(); } } - sendVerificationRequest(userId, verificationId, ivs); + sendVerificationRequest(verificationId, ivs); } mCurrentIntentFilterVerifications.clear(); } - private void sendVerificationRequest(int userId, int verificationId, - IntentFilterVerificationState ivs) { - + private void sendVerificationRequest(int verificationId, IntentFilterVerificationState ivs) { Intent verificationIntent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); verificationIntent.putExtra( PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID, @@ -1084,10 +1082,9 @@ public class PackageManagerService extends IPackageManager.Stub DeviceIdleController.LocalService idleController = getDeviceIdleController(); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(), - userId, false, "intent filter verifier"); + UserHandle.USER_SYSTEM, true, "intent filter verifier"); - UserHandle user = new UserHandle(userId); - mContext.sendBroadcastAsUser(verificationIntent, user); + mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM); if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Sending IntentFilter verification broadcast"); } @@ -7178,16 +7175,13 @@ public class PackageManagerService extends IPackageManager.Stub */ private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos, String ephemeralPkgName) { - // TODO: When adding on-demand split support for non-instant apps, remove this check - // and always apply post filtering - if (ephemeralPkgName == null) { - return resolveInfos; - } for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp(); + // TODO: When adding on-demand split support for non-instant apps, remove this check + // and always apply post filtering // allow activities that are defined in the provided package - if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) { + if (isEphemeralApp) { if (info.activityInfo.splitName != null && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames, info.activityInfo.splitName)) { @@ -7212,6 +7206,10 @@ public class PackageManagerService extends IPackageManager.Stub } continue; } + // caller is a full app, don't need to apply any other filtering + if (ephemeralPkgName == null) { + continue; + } // allow activities that have been explicitly exposed to ephemeral apps if (!isEphemeralApp && ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5c6521b1a8b6..89dbc2a1c1c4 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -23,6 +23,7 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.AppOpsManager.OP_TOAST_WINDOW; +import static android.content.Context.CONTEXT_RESTRICTED; import static android.content.Context.DISPLAY_SERVICE; import static android.content.Context.WINDOW_SERVICE; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; @@ -2823,7 +2824,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (theme != context.getThemeResId() || labelRes != 0) { try { - context = context.createPackageContext(packageName, 0); + context = context.createPackageContext(packageName, CONTEXT_RESTRICTED); context.setTheme(theme); } catch (PackageManager.NameNotFoundException e) { // Ignore diff --git a/services/core/java/com/android/server/radio/RadioService.java b/services/core/java/com/android/server/radio/RadioService.java index 87a6fc1ea5ce..8b0d3aa44ac0 100644 --- a/services/core/java/com/android/server/radio/RadioService.java +++ b/services/core/java/com/android/server/radio/RadioService.java @@ -24,16 +24,12 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.os.ParcelableException; -import android.util.Slog; import com.android.server.SystemService; import java.util.List; public class RadioService extends SystemService { - // TODO(b/36863239): rename to RadioService when native service goes away - private static final String TAG = "RadioServiceJava"; - private final RadioServiceImpl mServiceImpl = new RadioServiceImpl(); /** @@ -63,7 +59,6 @@ public class RadioService extends SystemService { @Override public void onStart() { publishBinderService(Context.RADIO_SERVICE, mServiceImpl); - Slog.v(TAG, "RadioService started"); } private class RadioServiceImpl extends IRadioService.Stub { diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 2d7fc6883292..6b514552b227 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -427,8 +427,9 @@ public class DockedStackDividerController implements DimLayerUser { inputMethodManagerInternal.hideCurrentInputMethod(); mImeHideRequested = true; } + return; } - setMinimizedDockedStack(false, false /* animate */); + setMinimizedDockedStack(false /* minimizedDock */, false /* animate */); } /** diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 091e1cba43a2..22b0f5bcdf07 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; @@ -37,6 +38,7 @@ import android.os.Parcel; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.Trace; import android.os.UserHandle; import android.util.MergedConfiguration; import android.util.Slog; @@ -85,6 +87,7 @@ public class Session extends IWindowSession.Stub private boolean mClientDead = false; private float mLastReportedAnimatorScale; private String mPackageName; + private String mRelayoutTag; public Session(WindowManagerService service, IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { @@ -224,10 +227,12 @@ public class Session extends IWindowSession.Stub MergedConfiguration mergedConfiguration, Surface outSurface) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); int res = mService.relayoutWindow(this, window, seq, attrs, requestedWidth, requestedHeight, viewFlags, flags, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); return res; @@ -575,6 +580,7 @@ public class Session extends IWindowSession.Stub void windowAddedLocked(String packageName) { mPackageName = packageName; + mRelayoutTag = "relayoutWindow: " + mPackageName; if (mSurfaceSession == null) { if (WindowManagerService.localLOGV) Slog.v( TAG_WM, "First window added to " + this + ", creating SurfaceSession"); @@ -698,6 +704,7 @@ public class Session extends IWindowSession.Stub pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces); pw.print(" mClientDead="); pw.print(mClientDead); pw.print(" mSurfaceSession="); pw.println(mSurfaceSession); + pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName); } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0c2ca859a31f..f9d7c3704341 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -30,6 +30,7 @@ import static android.os.Process.SHELL_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_DISPLAY; import static android.os.Process.myPid; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.UserHandle.USER_NULL; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -892,11 +893,16 @@ public class WindowManagerService extends IWindowManager.Stub } void openSurfaceTransaction() { - synchronized (mWindowMap) { - if (mRoot.mSurfaceTraceEnabled) { - mRoot.mRemoteEventTrace.openSurfaceTransaction(); + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction"); + synchronized (mWindowMap) { + if (mRoot.mSurfaceTraceEnabled) { + mRoot.mRemoteEventTrace.openSurfaceTransaction(); + } + SurfaceControl.openTransaction(); } - SurfaceControl.openTransaction(); + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @@ -912,16 +918,21 @@ public class WindowManagerService extends IWindowManager.Stub * blocks and we call it repeatedly, like we do for animations. */ void closeSurfaceTransaction(boolean withLockHeld) { - synchronized (mWindowMap) { - if (mRoot.mSurfaceTraceEnabled) { - mRoot.mRemoteEventTrace.closeSurfaceTransaction(); + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction"); + synchronized (mWindowMap) { + if (mRoot.mSurfaceTraceEnabled) { + mRoot.mRemoteEventTrace.closeSurfaceTransaction(); + } + if (withLockHeld) { + SurfaceControl.closeTransaction(); + } } - if (withLockHeld) { + if (!withLockHeld) { SurfaceControl.closeTransaction(); } - } - if (!withLockHeld) { - SurfaceControl.closeTransaction(); + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @@ -1996,6 +2007,8 @@ public class WindowManagerService extends IWindowManager.Stub (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING || !win.mAppToken.isClientHidden())) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1"); + // We are about to create a surface, but we didn't run a layout yet. So better run // a layout now that we already know the right size, as a resize call will make the // surface transaction blocking until next vsync and slow us down. @@ -2007,6 +2020,7 @@ public class WindowManagerService extends IWindowManager.Stub } result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges, oldVisibility); + try { result = createSurfaceControl(outSurface, result, win, winAnimator); } catch (Exception e) { @@ -2026,7 +2040,10 @@ public class WindowManagerService extends IWindowManager.Stub imMayMove = true; } win.adjustStartingWindowFlags(); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } else { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_2"); + winAnimator.mEnterAnimationPending = false; winAnimator.mEnteringAnimation = false; final boolean usingSavedSurfaceBeforeVisible = @@ -2061,18 +2078,22 @@ public class WindowManagerService extends IWindowManager.Stub // We already told the client to go invisible, but the message may not be // handled yet, or it might want to draw a last frame. If we already have a // surface, let the client use that, but don't create new surface at this point. + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface"); winAnimator.mSurfaceController.getSurface(outSurface); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } else { if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win); try { - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_" + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_" + win.mAttrs.getTitle()); outSurface.release(); } finally { - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } + + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } if (focusMayChange) { @@ -2109,8 +2130,11 @@ public class WindowManagerService extends IWindowManager.Stub } win.setDisplayLayoutNeeded(); - win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; + win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, + "relayoutWindow: updateOrientationFromAppTokens"); configChanged = updateOrientationFromAppTokensLocked(false, displayId); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); // We may be deferring layout passes at the moment, but since the client is interested // in the new out values right now we need to force a layout. @@ -2163,7 +2187,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (configChanged) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration"); sendNewConfiguration(displayId); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } Binder.restoreCallingIdentity(origId); return result; @@ -2224,8 +2250,14 @@ public class WindowManagerService extends IWindowManager.Stub if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; } - WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked( - win.mAttrs.type, win.mOwnerUid); + + WindowSurfaceController surfaceController; + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl"); + surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid); + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } if (surfaceController != null) { surfaceController.getSurface(outSurface); if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied"); @@ -2235,6 +2267,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG_WM, "Failed to create surface control for " + win); outSurface.release(); } + return result; } @@ -2281,7 +2314,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked"); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked"); if (okToDisplay()) { final DisplayContent displayContent = atoken.getTask().getDisplayContent(); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); @@ -2337,7 +2370,7 @@ public class WindowManagerService extends IWindowManager.Stub } else { atoken.mAppAnimator.clearAnimation(); } - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return atoken.mAppAnimator.animation != null; } @@ -3424,7 +3457,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!mBootAnimationStopped) { // Do this one time. - Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0); + Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0); try { IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); if (surfaceFlinger != null) { @@ -3447,7 +3480,7 @@ public class WindowManagerService extends IWindowManager.Stub } EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis()); - Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0); + Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0); mDisplayEnabled = true; if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!"); @@ -3678,12 +3711,12 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } try { - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */, -1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */, Bitmap.Config.ARGB_8888, true /* wallpaperOnly */, false /* includeDecor */); } finally { - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @@ -3869,6 +3902,8 @@ public class WindowManagerService extends IWindowManager.Stub + " alwaysSendConfiguration=" + alwaysSendConfiguration + " forceRelayout=" + forceRelayout); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation"); + long origId = Binder.clearCallingIdentity(); try { @@ -3877,20 +3912,28 @@ public class WindowManagerService extends IWindowManager.Stub final int displayId; synchronized (mWindowMap) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display"); rotationChanged = displayContent.updateRotationUnchecked( false /* inTransaction */); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (!rotationChanged || forceRelayout) { displayContent.setLayoutNeeded(); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, + "updateRotation: performSurfacePlacement"); mWindowPlacerLocked.performSurfacePlacement(); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } displayId = displayContent.getDisplayId(); } if (rotationChanged || alwaysSendConfiguration) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: sendNewConfiguration"); sendNewConfiguration(displayId); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } finally { Binder.restoreCallingIdentity(origId); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } @@ -5855,7 +5898,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { WindowState newFocus = mRoot.computeFocusedWindow(); if (mCurrentFocus != newFocus) { - Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus"); + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus"); // This check makes sure that we don't already have the focus // change message pending. mH.removeMessages(H.REPORT_FOCUS_CHANGE); @@ -5931,7 +5974,7 @@ public class WindowManagerService extends IWindowManager.Stub // other apps' UI. displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus); - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return true; } return false; diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index edbdf8bc5ed9..27927e6c0693 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; @@ -33,6 +34,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.IBinder; import android.os.Debug; +import android.os.Trace; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -101,8 +103,10 @@ class WindowSurfaceController { mSurfaceControl = new SurfaceTrace( s, name, w, h, format, flags, windowType, ownerUid); } else { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl"); mSurfaceControl = new SurfaceControl( s, name, w, h, format, flags, windowType, ownerUid); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } if (mService.mRoot.mSurfaceTraceEnabled) { diff --git a/services/core/jni/com_android_server_radio_RadioService.cpp b/services/core/jni/com_android_server_radio_RadioService.cpp index 2e0fbfd40ede..fa64901caee9 100644 --- a/services/core/jni/com_android_server_radio_RadioService.cpp +++ b/services/core/jni/com_android_server_radio_RadioService.cpp @@ -199,10 +199,10 @@ static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jin HalRevision halRev; if (V1_1::IBroadcastRadio::castFrom(module).withDefault(nullptr) != nullptr) { - ALOGI("Opening tuner with broadcast radio HAL 1.1"); + ALOGI("Opening tuner %d with broadcast radio HAL 1.1", moduleId); halRev = HalRevision::V1_1; } else { - ALOGI("Opening tuner with broadcast radio HAL 1.0"); + ALOGI("Opening tuner %d with broadcast radio HAL 1.0", moduleId); halRev = HalRevision::V1_0; } @@ -233,7 +233,7 @@ static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jin } Tuner::setHalTuner(env, tuner, halTuner); - ALOGI("Opened tuner %p", halTuner.get()); + ALOGD("Opened tuner %p", halTuner.get()); return tuner.release(); } diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp index f9418e4c108e..4b6f30b1c09f 100644 --- a/services/core/jni/com_android_server_radio_Tuner.cpp +++ b/services/core/jni/com_android_server_radio_Tuner.cpp @@ -150,7 +150,7 @@ void setHalTuner(JNIEnv *env, JavaRef<jobject> const &jTuner, sp<V1_0::ITuner> h auto& ctx = getNativeContext(env, jTuner); if (ctx.mIsClosed) { - ALOGI("Tuner was closed during initialization"); + ALOGD("Tuner was closed during initialization"); // dropping the last reference will close HAL tuner return; } diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index ede2b3ae01ec..f09ec6e660bd 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -20,16 +20,17 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import android.content.Context; -import android.net.apf.ApfCapabilities; -import android.net.apf.ApfFilter; import android.net.DhcpResults; +import android.net.INetd; import android.net.InterfaceConfiguration; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.LinkProperties.ProvisioningChange; +import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; +import android.net.apf.ApfCapabilities; +import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; @@ -38,7 +39,9 @@ import android.os.INetworkManagementService; import android.os.Message; import android.os.RemoteException; 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; @@ -319,6 +322,16 @@ public class IpManager extends StateMachine { return this; } + public Builder withIPv6AddrGenModeEUI64() { + mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64; + return this; + } + + public Builder withIPv6AddrGenModeStablePrivacy() { + mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; + return this; + } + public ProvisioningConfiguration build() { return new ProvisioningConfiguration(mConfig); } @@ -331,6 +344,7 @@ public class IpManager extends StateMachine { /* package */ StaticIpConfiguration mStaticIpConfig; /* package */ ApfCapabilities mApfCapabilities; /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS; + /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; public ProvisioningConfiguration() {} @@ -354,6 +368,7 @@ public class IpManager extends StateMachine { .add("mStaticIpConfig: " + mStaticIpConfig) .add("mApfCapabilities: " + mApfCapabilities) .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs) + .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode) .toString(); } } @@ -1044,16 +1059,25 @@ public class IpManager extends StateMachine { return true; } + private void setIPv6AddrGenModeIfSupported() throws RemoteException { + try { + mNwService.setIPv6AddrGenMode(mInterfaceName, mConfiguration.mIPv6AddrGenMode); + } catch (ServiceSpecificException e) { + if (e.errorCode != OsConstants.EOPNOTSUPP) { + throw e; + } + } + } + private boolean startIPv6() { // Set privacy extensions. try { mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); + + setIPv6AddrGenModeIfSupported(); mNwService.enableIpv6(mInterfaceName); - } catch (RemoteException re) { - logError("Unable to change interface settings: %s", re); - return false; - } catch (IllegalStateException ie) { - logError("Unable to change interface settings: %s", ie); + } catch (IllegalStateException | RemoteException | ServiceSpecificException e) { + logError("Unable to change interface settings: %s", e); return false; } diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index ebad81cdda34..5e5ba462cfca 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -816,6 +816,12 @@ public class MockContext extends Context { /** {@hide} */ @Override + public boolean canLoadUnsafeResources() { + throw new UnsupportedOperationException(); + } + + /** {@hide} */ + @Override public IBinder getActivityToken() { throw new UnsupportedOperationException(); } diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk index 68fd6621718c..cc9b01d18fa6 100644 --- a/test-runner/tests/Android.mk +++ b/test-runner/tests/Android.mk @@ -16,6 +16,13 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) # We only want this apk build for tests. +# +# Run the tests using the following commands: +# adb -r install ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk +# adb shell am instrument \ + -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \ + -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner +# LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := android.test.runner diff --git a/test-runner/tests/src/android/test/TestCaseUtilTest.java b/test-runner/tests/src/android/test/TestCaseUtilTest.java index bc6fa9200d1b..9d12eafcd34f 100644 --- a/test-runner/tests/src/android/test/TestCaseUtilTest.java +++ b/test-runner/tests/src/android/test/TestCaseUtilTest.java @@ -29,9 +29,7 @@ public class TestCaseUtilTest extends TestCase { List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testSuite, false); - assertEquals(2, testCaseNames.size()); - assertTrue(testCaseNames.get(0).endsWith("OneTestTestCase")); - assertTrue(testCaseNames.get(1).endsWith("OneTestTestSuite")); + assertEquals(0, testCaseNames.size()); } public void testGetTestCaseNamesForTestCaseWithSuiteMethod() throws Exception { diff --git a/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java index 293c8133eb95..a2e51a197a98 100644 --- a/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java +++ b/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java @@ -135,10 +135,23 @@ public class TestSuiteBuilderTest extends TestCase { TestSuite testSuite = new OuterTest().buildTestsUnderHereRecursively(); assertContentsInOrder(getTestCaseNames(testSuite), - "testOuter", "testErrorOne", "testErrorTwo", "testFailOne", "testFailTwo", - "testInstrumentation", "testLevel1", "testLevel2", "testAnotherOne", - "testSimpleOne", "testSimpleTwo", "testNonSmoke", "testSmoke", "testSubclass", - "testSuperclass", "testUnSuppressedMethod"); + "testOuter", + "testPublicConstructor", + "testErrorOne", + "testErrorTwo", + "testFailOne", + "testFailTwo", + "testInstrumentation", + "testLevel1", + "testLevel2", + "testAnotherOne", + "testSimpleOne", + "testSimpleTwo", + "testNonSmoke", + "testSmoke", + "testSubclass", + "testSuperclass", + "testUnSuppressedMethod"); } private void assertContentsInOrder(List<String> actual, String... source) { diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java index f1f6113e86d2..ddf5dd16ece9 100644 --- a/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java +++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java @@ -18,6 +18,7 @@ package android.test.suitebuilder.examples.error; import junit.framework.TestCase; +@RunAsPartOfSeparateTest public class ErrorTest extends TestCase { public void testErrorOne() throws Exception { diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java index 428fd23b819d..0170b2f6cc70 100644 --- a/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java +++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java @@ -18,6 +18,7 @@ package android.test.suitebuilder.examples.error; import junit.framework.TestCase; +@RunAsPartOfSeparateTest public class FailingTest extends TestCase { public void testFailOne() throws Exception { diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java new file mode 100644 index 000000000000..2b3a2528a39a --- /dev/null +++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java @@ -0,0 +1,30 @@ +/* + * 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.test.suitebuilder.examples.error; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that marks tests that should only be run as part of a separate test and not on their + * own. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface RunAsPartOfSeparateTest { +} diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 0d69c892c103..9d71775889d4 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -40,7 +40,7 @@ using ::aapt::configuration::Abi; using ::aapt::configuration::Artifact; -using ::aapt::configuration::Configuration; +using ::aapt::configuration::PostProcessingConfiguration; using ::android::StringPiece; using ::android::base::StringPrintf; @@ -66,8 +66,7 @@ struct OptimizeOptions { TableFlattenerOptions table_flattener_options; - // TODO: Come up with a better name for the Configuration struct. - Maybe<Configuration> configuration; + Maybe<PostProcessingConfiguration> configuration; }; class OptimizeContext : public IAaptContext { @@ -189,7 +188,7 @@ class OptimizeCommand { } if (options_.configuration && options_.output_dir) { - Configuration& config = options_.configuration.value(); + PostProcessingConfiguration& config = options_.configuration.value(); // For now, just write out the stripped APK since ABI splitting doesn't modify anything else. for (const Artifact& artifact : config.artifacts) { diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp index 555cb35c0bb9..0b6743c4c3b6 100644 --- a/tools/aapt2/configuration/ConfigurationParser.cpp +++ b/tools/aapt2/configuration/ConfigurationParser.cpp @@ -42,7 +42,7 @@ using ::aapt::configuration::Abi; using ::aapt::configuration::AndroidManifest; using ::aapt::configuration::AndroidSdk; using ::aapt::configuration::Artifact; -using ::aapt::configuration::Configuration; +using ::aapt::configuration::PostProcessingConfiguration; using ::aapt::configuration::GlTexture; using ::aapt::configuration::Group; using ::aapt::configuration::Locale; @@ -125,7 +125,7 @@ ConfigurationParser::ConfigurationParser(std::string contents) diag_(&noop_) { } -Maybe<Configuration> ConfigurationParser::Parse() { +Maybe<PostProcessingConfiguration> ConfigurationParser::Parse() { std::istringstream in(contents_); auto doc = xml::Inflate(&in, diag_, Source("config.xml")); @@ -157,10 +157,11 @@ Maybe<Configuration> ConfigurationParser::Parse() { XmlNodeAction& artifacts_action = root_action["artifacts"]; XmlNodeAction& groups_action = root_action["groups"]; - Configuration config; + PostProcessingConfiguration config; // Helper to bind a static method to an action handler in the DOM executor. - auto bind_handler = [&config](std::function<bool(Configuration*, Element*, IDiagnostics*)> h) + auto bind_handler = + [&config](std::function<bool(PostProcessingConfiguration*, Element*, IDiagnostics*)> h) -> XmlNodeAction::ActionFuncWithDiag { return std::bind(h, &config, std::placeholders::_1, std::placeholders::_2); }; @@ -189,271 +190,259 @@ Maybe<Configuration> ConfigurationParser::Parse() { } ConfigurationParser::ActionHandler ConfigurationParser::artifact_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - Artifact artifact{}; - for (const auto& attr : root_element->attributes) { - if (attr.name == "name") { - artifact.name = attr.value; - } else if (attr.name == "abi-group") { - artifact.abi_group = {attr.value}; - } else if (attr.name == "screen-density-group") { - artifact.screen_density_group = {attr.value}; - } else if (attr.name == "locale-group") { - artifact.locale_group = {attr.value}; - } else if (attr.name == "android-sdk-group") { - artifact.android_sdk_group = {attr.value}; - } else if (attr.name == "gl-texture-group") { - artifact.gl_texture_group = {attr.value}; - } else if (attr.name == "device-feature-group") { - artifact.device_feature_group = {attr.value}; - } else { - diag->Note( - DiagMessage() << "Unknown artifact attribute: " << attr.name << " = " << attr.value); - } - } - config->artifacts.push_back(artifact); - return true; - }; + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + Artifact artifact{}; + for (const auto& attr : root_element->attributes) { + if (attr.name == "name") { + artifact.name = attr.value; + } else if (attr.name == "abi-group") { + artifact.abi_group = {attr.value}; + } else if (attr.name == "screen-density-group") { + artifact.screen_density_group = {attr.value}; + } else if (attr.name == "locale-group") { + artifact.locale_group = {attr.value}; + } else if (attr.name == "android-sdk-group") { + artifact.android_sdk_group = {attr.value}; + } else if (attr.name == "gl-texture-group") { + artifact.gl_texture_group = {attr.value}; + } else if (attr.name == "device-feature-group") { + artifact.device_feature_group = {attr.value}; + } else { + diag->Note(DiagMessage() << "Unknown artifact attribute: " << attr.name << " = " + << attr.value); + } + } + config->artifacts.push_back(artifact); + return true; +}; ConfigurationParser::ActionHandler ConfigurationParser::artifact_format_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - for (auto& node : root_element->children) { - xml::Text* t; - if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { - config->artifact_format = TrimWhitespace(t->text).to_string(); - break; - } - } - return true; - }; + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + for (auto& node : root_element->children) { + xml::Text* t; + if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { + config->artifact_format = TrimWhitespace(t->text).to_string(); + break; + } + } + return true; +}; ConfigurationParser::ActionHandler ConfigurationParser::abi_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - auto& group = config->abi_groups[label]; - bool valid = true; + auto& group = config->abi_groups[label]; + bool valid = true; - for (auto* child : root_element->GetChildElements()) { - if (child->name != "abi") { - diag->Error( - DiagMessage() << "Unexpected element in ABI group: " << child->name); - valid = false; - } else { - for (auto& node : child->children) { - xml::Text* t; - if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { - group.push_back(kStringToAbiMap.at(TrimWhitespace(t->text).to_string())); - break; - } - } + for (auto* child : root_element->GetChildElements()) { + if (child->name != "abi") { + diag->Error(DiagMessage() << "Unexpected element in ABI group: " << child->name); + valid = false; + } else { + for (auto& node : child->children) { + xml::Text* t; + if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { + group.push_back(kStringToAbiMap.at(TrimWhitespace(t->text).to_string())); + break; } } + } + } - return valid; - }; + return valid; +}; ConfigurationParser::ActionHandler ConfigurationParser::screen_density_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - auto& group = config->screen_density_groups[label]; - bool valid = true; + auto& group = config->screen_density_groups[label]; + bool valid = true; - for (auto* child : root_element->GetChildElements()) { - if (child->name != "screen-density") { - diag->Error( - DiagMessage() << "Unexpected root_element in screen density group: " - << child->name); - valid = false; - } else { - for (auto& node : child->children) { - xml::Text* t; - if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { - ConfigDescription config_descriptor; - const android::StringPiece& text = TrimWhitespace(t->text); - if (ConfigDescription::Parse(text, &config_descriptor)) { - // Copy the density with the minimum SDK version stripped out. - group.push_back(config_descriptor.CopyWithoutSdkVersion()); - } else { - diag->Error( - DiagMessage() << "Could not parse config descriptor for screen-density: " - << text); - valid = false; - } - break; - } + for (auto* child : root_element->GetChildElements()) { + if (child->name != "screen-density") { + diag->Error(DiagMessage() << "Unexpected root_element in screen density group: " + << child->name); + valid = false; + } else { + for (auto& node : child->children) { + xml::Text* t; + if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { + ConfigDescription config_descriptor; + const android::StringPiece& text = TrimWhitespace(t->text); + if (ConfigDescription::Parse(text, &config_descriptor)) { + // Copy the density with the minimum SDK version stripped out. + group.push_back(config_descriptor.CopyWithoutSdkVersion()); + } else { + diag->Error(DiagMessage() + << "Could not parse config descriptor for screen-density: " << text); + valid = false; } + break; } } + } + } - return valid; - }; + return valid; +}; ConfigurationParser::ActionHandler ConfigurationParser::locale_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - auto& group = config->locale_groups[label]; - bool valid = true; + auto& group = config->locale_groups[label]; + bool valid = true; - for (auto* child : root_element->GetChildElements()) { - if (child->name != "locale") { - diag->Error( - DiagMessage() << "Unexpected root_element in screen density group: " - << child->name); - valid = false; + for (auto* child : root_element->GetChildElements()) { + if (child->name != "locale") { + diag->Error(DiagMessage() << "Unexpected root_element in screen density group: " + << child->name); + valid = false; + } else { + Locale entry; + for (const auto& attr : child->attributes) { + if (attr.name == "lang") { + entry.lang = {attr.value}; + } else if (attr.name == "region") { + entry.region = {attr.value}; } else { - Locale entry; - for (const auto& attr : child->attributes) { - if (attr.name == "lang") { - entry.lang = {attr.value}; - } else if (attr.name == "region") { - entry.region = {attr.value}; - } else { - diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name - << " = " << attr.value); - } - } - group.push_back(entry); + diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value); } } + group.push_back(entry); + } + } - return valid; - }; + return valid; +}; ConfigurationParser::ActionHandler ConfigurationParser::android_sdk_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } - - auto& group = config->android_sdk_groups[label]; - bool valid = true; + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - for (auto* child : root_element->GetChildElements()) { - if (child->name != "android-sdk") { - diag->Error( - DiagMessage() << "Unexpected root_element in ABI group: " << child->name); - valid = false; + auto& group = config->android_sdk_groups[label]; + bool valid = true; + + for (auto* child : root_element->GetChildElements()) { + if (child->name != "android-sdk") { + diag->Error(DiagMessage() << "Unexpected root_element in ABI group: " << child->name); + valid = false; + } else { + AndroidSdk entry; + for (const auto& attr : child->attributes) { + if (attr.name == "minSdkVersion") { + entry.min_sdk_version = {attr.value}; + } else if (attr.name == "targetSdkVersion") { + entry.target_sdk_version = {attr.value}; + } else if (attr.name == "maxSdkVersion") { + entry.max_sdk_version = {attr.value}; } else { - AndroidSdk entry; - for (const auto& attr : child->attributes) { - if (attr.name == "minSdkVersion") { - entry.min_sdk_version = {attr.value}; - } else if (attr.name == "targetSdkVersion") { - entry.target_sdk_version = {attr.value}; - } else if (attr.name == "maxSdkVersion") { - entry.max_sdk_version = {attr.value}; - } else { - diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name - << " = " << attr.value); - } - } + diag->Warn(DiagMessage() << "Unknown attribute: " << attr.name << " = " << attr.value); + } + } - // TODO: Fill in the manifest details when they are finalised. - for (auto node : child->GetChildElements()) { - if (node->name == "manifest") { - if (entry.manifest) { - diag->Warn(DiagMessage() << "Found multiple manifest tags. Ignoring duplicates."); - continue; - } - entry.manifest = {AndroidManifest()}; - } + // TODO: Fill in the manifest details when they are finalised. + for (auto node : child->GetChildElements()) { + if (node->name == "manifest") { + if (entry.manifest) { + diag->Warn(DiagMessage() << "Found multiple manifest tags. Ignoring duplicates."); + continue; } - - group.push_back(entry); + entry.manifest = {AndroidManifest()}; } } - return valid; - }; + group.push_back(entry); + } + } + + return valid; +}; ConfigurationParser::ActionHandler ConfigurationParser::gl_texture_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - auto& group = config->gl_texture_groups[label]; - bool valid = true; + auto& group = config->gl_texture_groups[label]; + bool valid = true; - GlTexture result; - for (auto* child : root_element->GetChildElements()) { - if (child->name != "gl-texture") { - diag->Error( - DiagMessage() << "Unexpected element in GL texture group: " - << child->name); - valid = false; - } else { - for (const auto& attr : child->attributes) { - if (attr.name == "name") { - result.name = attr.value; - break; - } - } + GlTexture result; + for (auto* child : root_element->GetChildElements()) { + if (child->name != "gl-texture") { + diag->Error(DiagMessage() << "Unexpected element in GL texture group: " << child->name); + valid = false; + } else { + for (const auto& attr : child->attributes) { + if (attr.name == "name") { + result.name = attr.value; + break; + } + } - for (auto* element : child->GetChildElements()) { - if (element->name != "texture-path") { - diag->Error( - DiagMessage() << "Unexpected element in gl-texture element: " - << child->name); - valid = false; - continue; - } - for (auto& node : element->children) { - xml::Text* t; - if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { - result.texture_paths.push_back(TrimWhitespace(t->text).to_string()); - } - } + for (auto* element : child->GetChildElements()) { + if (element->name != "texture-path") { + diag->Error(DiagMessage() << "Unexpected element in gl-texture element: " << child->name); + valid = false; + continue; + } + for (auto& node : element->children) { + xml::Text* t; + if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { + result.texture_paths.push_back(TrimWhitespace(t->text).to_string()); } } - group.push_back(result); } + } + group.push_back(result); + } - return valid; - }; + return valid; +}; ConfigurationParser::ActionHandler ConfigurationParser::device_feature_group_handler_ = - [](Configuration* config, Element* root_element, IDiagnostics* diag) -> bool { - std::string label = GetLabel(root_element, diag); - if (label.empty()) { - return false; - } + [](PostProcessingConfiguration* config, Element* root_element, IDiagnostics* diag) -> bool { + std::string label = GetLabel(root_element, diag); + if (label.empty()) { + return false; + } - auto& group = config->device_feature_groups[label]; - bool valid = true; + auto& group = config->device_feature_groups[label]; + bool valid = true; - for (auto* child : root_element->GetChildElements()) { - if (child->name != "supports-feature") { - diag->Error( - DiagMessage() << "Unexpected root_element in device feature group: " - << child->name); - valid = false; - } else { - for (auto& node : child->children) { - xml::Text* t; - if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { - group.push_back(TrimWhitespace(t->text).to_string()); - break; - } - } + for (auto* child : root_element->GetChildElements()) { + if (child->name != "supports-feature") { + diag->Error(DiagMessage() << "Unexpected root_element in device feature group: " + << child->name); + valid = false; + } else { + for (auto& node : child->children) { + xml::Text* t; + if ((t = NodeCast<xml::Text>(node.get())) != nullptr) { + group.push_back(TrimWhitespace(t->text).to_string()); + break; } } + } + } - return valid; - }; + return valid; +}; } // namespace aapt diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h index 0435cbf72a22..3fae5dd0a990 100644 --- a/tools/aapt2/configuration/ConfigurationParser.h +++ b/tools/aapt2/configuration/ConfigurationParser.h @@ -117,10 +117,8 @@ struct GlTexture { } }; -/** - * AAPT2 XML configuration binary representation. - */ -struct Configuration { +/** AAPT2 XML configuration file binary representation. */ +struct PostProcessingConfiguration { // TODO: Support named artifacts? std::vector<Artifact> artifacts; Maybe<std::string> artifact_format; @@ -166,7 +164,7 @@ class ConfigurationParser { * Parses the configuration file and returns the results. If the configuration could not be parsed * the result is empty and any errors will be displayed with the provided diagnostics context. */ - Maybe<configuration::Configuration> Parse(); + Maybe<configuration::PostProcessingConfiguration> Parse(); protected: /** @@ -185,9 +183,8 @@ class ConfigurationParser { * An ActionHandler for processing XML elements in the XmlActionExecutor. Returns true if the * element was successfully processed, otherwise returns false. */ - using ActionHandler = std::function<bool(configuration::Configuration* config, - xml::Element* element, - IDiagnostics* diag)>; + using ActionHandler = std::function<bool(configuration::PostProcessingConfiguration* config, + xml::Element* element, IDiagnostics* diag)>; /** Handler for <artifact> tags. */ static ActionHandler artifact_handler_; diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp index a8c385823fa9..a4fa1344cb3b 100644 --- a/tools/aapt2/configuration/ConfigurationParser_test.cpp +++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp @@ -32,7 +32,7 @@ namespace { using android::ResTable_config; using configuration::Abi; using configuration::AndroidSdk; -using configuration::Configuration; +using configuration::PostProcessingConfiguration; using configuration::DeviceFeature; using configuration::GlTexture; using configuration::Locale; @@ -139,7 +139,7 @@ TEST_F(ConfigurationParserTest, ValidateFile) { auto parser = ConfigurationParser::ForContents(kValidConfig).WithDiagnostics(&diag_); auto result = parser.Parse(); ASSERT_TRUE(result); - Configuration& value = result.value(); + PostProcessingConfiguration& value = result.value(); EXPECT_EQ(2ul, value.artifacts.size()); ASSERT_TRUE(value.artifact_format); EXPECT_EQ( @@ -190,7 +190,7 @@ TEST_F(ConfigurationParserTest, ArtifactAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = artifact_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -229,7 +229,7 @@ TEST_F(ConfigurationParserTest, ArtifactFormatAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = artifact_format_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); ASSERT_TRUE(config.artifact_format); @@ -252,7 +252,7 @@ TEST_F(ConfigurationParserTest, AbiGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = abi_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -275,7 +275,7 @@ TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = screen_density_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -305,7 +305,7 @@ TEST_F(ConfigurationParserTest, LocaleGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = locale_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -341,7 +341,7 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = android_sdk_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -373,7 +373,7 @@ TEST_F(ConfigurationParserTest, GlTextureGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = gl_texture_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); @@ -402,7 +402,7 @@ TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) { auto doc = test::BuildXmlDom(xml); - Configuration config; + PostProcessingConfiguration config; bool ok = device_feature_group_handler_(&config, NodeCast<Element>(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); |